@Autowired and Qualifier Selection
@Autowired and Qualifier Selection
Even with modern constructor injection, you will meet @Autowired and friends in existing code, and you will eventually need qualifiers to choose among several beans of the same type. Both are straightforward once you know the rules and why injection can fail.
How @Autowired resolves
@Autowired on a field, constructor, or setter tells Spring to find a matching bean. Resolution is by type first. If exactly one candidate exists, it wins. If several do, Spring then looks at the parameter or field name as a hint, and finally at qualifiers.
Constructor injection without the annotation
With a single constructor, Spring forgoes the annotation entirely. That style is preferred today: the compiler guarantees required dependencies, and the wiring is visible in the constructor signature alone.
@Service
public class ReportService {
private final ReportFormatter formatter;
@Autowired
public ReportService(
@Qualifier("premiumFormatter") ReportFormatter formatter) {
this.formatter = formatter;
}
}
Qualifiers
When multiple beans match a type, the primary strategy is to name one as the default with @Primary. For finer control, give beans qualifiers and request them with @Qualifier("name"). Your own annotations composed with @Qualifier can carry semantics instead of bare strings.
Diagnosing failures
No candidates produce NoSuchBeanDefinitionException; multiple candidates without a tiebreaker produce NoUniqueBeanDefinitionException. Both fail fast at startup, which is a feature. Read the message: it lists the candidates, then add @Primary or @Qualifier to resolve it.
Key Points
- Injection resolves by type, then name, then qualifier.
- Single-constructor injection works without any annotation.
- Use
@Primaryfor a default and@Qualifierfor explicit picks. - Startup exceptions list candidate beans to guide your fix.
- Prefer constructor injection for required dependencies.