惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

月光博客
月光博客
Cyberwarzone
Cyberwarzone
L
LINUX DO - 最新话题
N
News and Events Feed by Topic
T
Troy Hunt's Blog
Help Net Security
Help Net Security
S
Security @ Cisco Blogs
Google DeepMind News
Google DeepMind News
Security Archives - TechRepublic
Security Archives - TechRepublic
M
MIT News - Artificial intelligence
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V2EX - 技术
V2EX - 技术
Y
Y Combinator Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
大猫的无限游戏
大猫的无限游戏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
T
Threatpost
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
SegmentFault 最新的问题
I
InfoQ
H
Hacker News: Front Page
D
Docker
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Blog — PlanetScale
Blog — PlanetScale
人人都是产品经理
人人都是产品经理
博客园 - 叶小钗
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
Netflix TechBlog - Medium
AWS News Blog
AWS News Blog
Know Your Adversary
Know Your Adversary
博客园 - 【当耐特】
T
Tor Project blog
U
Unit 42
H
Heimdal Security Blog
Microsoft Azure Blog
Microsoft Azure Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Privacy & Cybersecurity Law Blog
PCI Perspectives
PCI Perspectives
美团技术团队
O
OpenAI News
T
Tailwind CSS Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog
GbyAI
GbyAI
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
MyScale Blog
MyScale Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
@Autowired resolution, @Qualifier/@Primary, injection types + circular-dependency gotcha
Ankit Verma · 2026-06-15 · via DEV Community

The last article left the container in a tidy state. Scanning has finished, and every class you marked is now a bean definition sitting in the container, names and all. But a definition is just a recipe. The moment the container starts actually building beans, it hits the question this article is about: to build OrderService, it needs to pass something into the PaymentGateway slot in its constructor — so which bean does it reach for?

When exactly one bean fits, the answer is obvious and you never think about it. The interesting part is everything around that happy path: how the container makes the match, what happens when two beans fit the same slot, and how you steer the choice when it can't decide on its own.

That whole job — the container finding and supplying the beans a dependency needs, instead of you naming each one by hand — is called autowiring. You meet it for real the first time Spring refuses to start, complaining it found more than one bean of some type and doesn't know which you meant. To fix that on purpose instead of by trial and error, you need to see how resolution actually works.

This article walks it end to end: the match by type, why @Autowired is often already implied, the ambiguity that breaks the match, the three tools that break the tie, what to do when a bean might be missing — and finally a deeper look at the circular-dependency trap the dependency-injection article only cracked open.

The happy path: resolution by type

Start with the rule from the dependency-injection article, now seen from the container's side. When the container builds a bean and reaches a dependency, it looks through every bean it knows about for one whose type fits, and injects that one.

@Service
class OrderService {
    private final PaymentGateway gateway;

    OrderService(PaymentGateway gateway) {   // "I need a PaymentGateway"
        this.gateway = gateway;
    }
}

If there is exactly one PaymentGateway bean in the container, the match is unambiguous and the wiring just happens. You declared a need by type; the container found the one bean that satisfies it and handed it over. That is autowiring in its simplest, invisible form.

Where did @Autowired go?

You may have noticed there is no @Autowired on that constructor. That is not an oversight. When a class has a single constructor, Spring treats it as an injection point automatically — it assumes the parameters are dependencies to resolve, no annotation required.

So @Autowired only needs to appear in the cases Spring cannot infer:

  • On a class with more than one constructor, to mark which one the container should call.
  • On a field or setter, where there is no sole constructor for Spring to assume.
@Service
class OrderService {
    @Autowired                                  // needed here only if there are other constructors
    OrderService(PaymentGateway gateway) { /* ... */ }
}

The useful way to hold it: @Autowired marks an injection point — a spot that says "fill this in from the container." A parameter on a sole constructor is an injection point implicitly. Everywhere else, the annotation is how you point at one.

When two beans fit one slot

Now the situation that breaks the happy path. Suppose two classes implement the same interface, and both are beans:

@Component
class StripeGateway implements PaymentGateway { /* ... */ }

@Component
class AdyenGateway implements PaymentGateway { /* ... */ }

OrderService still asks for a single PaymentGateway. The container searches by type and now finds two candidates. It has no basis to prefer one, and it will not guess. It fails at startup:

NoUniqueBeanDefinitionException: expected single matching bean
but found 2: stripeGateway, adyenGateway

This is the fail-fast philosophy again — an ambiguous wiring is caught at boot, on your machine, not silently resolved into the wrong gateway in production. Spring gives you three ways to resolve it, and they are worth knowing as a set, because they layer.

Tie-breaker 1: the parameter name

Before you reach for any annotation, Spring has a quiet fallback already running. When the type matches several beans, it tries to narrow them by name — matching the name of the injection point against the bean names. Recall from the scanning article that a scanned bean is named after its class, decapitalized: StripeGateway becomes stripeGateway.

@Service
class OrderService {
    OrderService(PaymentGateway stripeGateway) {   // parameter name matches a bean name
        // resolves to the stripeGateway bean
    }
}

Name the parameter stripeGateway and the ambiguity disappears: the container matches it to the bean of that name. It works, but lean on it carefully. It depends on parameter names surviving compilation (Spring Boot compiles with that turned on, so they do), and it is subtle — renaming a parameter silently rewires the application. It is fine as a fallback; it is a poor way to express intent. For that, be explicit.

Tie-breaker 2: @Primary — declare a default winner

@Primary marks one bean as the default to use whenever several fit:

@Component
@Primary
class StripeGateway implements PaymentGateway { /* ... */ }

@Component
class AdyenGateway implements PaymentGateway { /* ... */ }

Now any unqualified PaymentGateway injection, anywhere in the app, gets Stripe. The key trait is that @Primary lives on the bean — one declaration, applied everywhere that type is needed. It is the right tool when there is one obvious default and only rare exceptions.

Tie-breaker 3: @Qualifier — name the one you want

@Primary decides globally. @Qualifier decides at a single injection point. You give the beans qualifier names and then ask for one by name right where you need it:

@Component
@Qualifier("stripe")
class StripeGateway implements PaymentGateway { /* ... */ }

@Component
@Qualifier("adyen")
class AdyenGateway implements PaymentGateway { /* ... */ }

@Service
class OrderService {
    OrderService(@Qualifier("stripe") PaymentGateway gateway) {   // this slot wants Stripe
        // ...
    }
}

And the two combine cleanly. When both are present, @Qualifier at the injection point wins over @Primary. The idiom that falls out: mark the everyday default with @Primary, and use @Qualifier only at the few spots that need the exception. Most of the code stays quiet; the deviations are explicit.

When the bean might not be there

The mirror image of ambiguity is absence. If a required dependency has no matching bean, the container fails at boot with NoSuchBeanDefinitionException — the same fail-fast instinct. Usually that is exactly what you want. But occasionally a dependency is genuinely optional: a metrics sink that may or may not be configured, say. Spring has three ways to say "inject it if it exists, otherwise carry on":

  • @Autowired(required = false) — leaves a field or setter unset if no bean is found.
  • Optional<PaymentGateway> — arrives empty when the bean is absent.
  • ObjectProvider<PaymentGateway> — a lazy handle you ask for the bean only when you need it (the same type the bean-scopes article used to pull a fresh prototype on demand).
@Service
class OrderService {
    private final Optional<PaymentGateway> gateway;

    OrderService(Optional<PaymentGateway> gateway) {   // empty if no gateway bean exists
        this.gateway = gateway;
    }
}

Prefer Optional or ObjectProvider over required = false: they keep the field final and make the "might be absent" part visible in the type, instead of hiding it behind a field that is sometimes null. (And note the List<PaymentGateway> form from the DI article is a different case entirely — it asks for all matching beans on purpose, so several matches are the answer, not an error.)

Injection types, seen through resolution

The DI article already made the case for constructor injection over setters and fields, so this is just the same picture from the resolver's angle: the matching algorithm above is identical no matter where the injection point sits. @Qualifier and @Primary work the same on a constructor parameter, a setter, or a field.

What changes is when resolution runs and how safely. Constructor injection resolves everything at construction, so the object is never half-built and the fields can be final. Setter injection runs during the populate stage, which suits a truly optional or reconfigurable dependency. Field injection is the most concise and the least testable. The resolution rules don't pick a style for you — but as the next section shows, the style you pick decides how one particular failure behaves.

The circular-dependency gotcha, in full

The DI article showed one slice of this: two beans that depend on each other, wired through constructors, fail at boot. Here is the complete picture, because the outcome depends entirely on the injection style — and that is the whole lesson.

Say A needs B, and B needs A. With constructor injection on both sides, neither object can be built first: building A needs a finished B, which needs a finished A, and round it goes. The container detects the loop and stops:

BeanCurrentlyInCreationException:
Requested bean is currently in creation  is there an unresolvable circular reference?

That looks like an obstacle. It is actually the good case — the cycle is exposed the instant you start the app.

Now switch the two beans to field injection and watch the failure quietly vanish:

@Component
class A {
    @Autowired B b;
}

@Component
class B {
    @Autowired A a;
}

Because field injection happens after construction, Spring has a move available that constructors deny it. It builds the raw A first, then — before A is fully wired — exposes a reference to that half-built A. It builds B, setting B's field to the early A reference. With B now complete, it finishes wiring A by setting A's field to the finished B. The cycle resolves, and the application starts as if nothing were wrong.

That "as if nothing were wrong" is the trap. A circular dependency is a real design flaw — two beans so entangled that neither is whole without the other — and field injection lets it ship undetected. Constructor injection would have failed loudly at boot and forced the conversation. This is one more reason the earlier articles pushed constructors so hard: the strictness is the safety.

Spring offers an escape hatch, @Lazy, for when you must break a cycle without redesigning right now. Put @Lazy on one of the two injection points and the container injects a proxy — the same stand-in trick from the first article — instead of the real bean, deferring the real lookup until the first method call. By then both beans exist, so the loop never has to be resolved at construction time.

@Component
class A {
    A(@Lazy B b) { /* ... */ }   // injects a proxy now, resolves B on first use
}

Treat that as a patch, not a cure. The honest fix is to break the cycle: pull the shared logic into a third bean both can depend on, or let one side publish an event the other listens for, the way the ApplicationContext article wired OrderService to email without either knowing the other. A mutual dependency almost always means a responsibility is living in the wrong class.

It is worth knowing that recent Spring Boot takes your side here: since 2.6 it forbids circular references by default, so even a field-injected cycle fails at startup unless you deliberately set spring.main.allow-circular-references=true. The framework now nudges everyone toward the fix instead of the papering-over.

Putting it together

Autowiring is the container resolving each dependency by type: one matching bean and the wiring is silent, with @Autowired implied on a sole constructor and only spelled out for extra constructors, fields, and setters. When two beans fit one slot, the container fails fast rather than guess — and you break the tie three ways: the parameter name (a subtle fallback), @Primary (one global default on the bean), or @Qualifier (a named choice at the injection point that overrides @Primary). When a bean might be missing, Optional or ObjectProvider make the absence explicit instead of crashing.

The deepest point is the one about cycles. Resolution itself doesn't care which injection style you used — but a circular dependency does. Constructor injection turns it into a boot-time error you cannot miss; field injection papers over it and lets a design flaw ship. That asymmetry, now reinforced by Boot's default of refusing cycles outright, is the last and strongest argument for wiring through the constructor.

With that, the container's whole story is on the table: how it learns what your beans are, builds them, scopes them, and now connects them to each other. The next article steps back from the individual mechanisms and ties the entire Foundations module into one mental model — a recap of how every piece we have built fits together.