Spring boot autowiring an interface with multiple implementations
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.
Introduction
Autowiring an interface in Spring Boot works automatically only when exactly one matching bean exists. Once you add multiple implementations, injection by type becomes ambiguous and Spring refuses to guess. The correct fix is to make the selection explicit, either at wiring time or by injecting all candidates and choosing deliberately.
Why Spring Throws an Ambiguity Error
Suppose you have one interface and two concrete services:
If another bean asks for PaymentService through constructor injection, Spring sees two candidates and throws NoUniqueBeanDefinitionException. That is expected behavior. By type alone, both beans are valid.
Use @Qualifier for an Explicit Choice
@Qualifier is the most direct solution when one class needs one specific implementation.
This works best when the dependency is stable and business logic clearly depends on one named implementation. If the bean name matters to the application design, make it explicit rather than relying on the default class-name-derived bean id.
Use @Primary for the Default Implementation
If one implementation should win in most cases, annotate it with @Primary.
Now plain PaymentService injection resolves to that bean unless a @Qualifier overrides it.
@Primary is a good fit when there is a natural default and a few special alternatives. It is a bad fit when the correct implementation depends on request content, tenant, or feature flags.
Inject a Collection for Strategy Selection
Sometimes the application genuinely needs multiple implementations at runtime. In that case, inject a List or Map of beans.
This pattern is useful for strategy selection. For example, a controller might choose a provider based on a request field, while keeping each payment implementation isolated and testable.
Profiles and Conditions Can Also Narrow the Set
If only one implementation should exist in a given environment, Spring profiles or conditional beans can prevent the ambiguity from existing in the first place.
This approach is different from @Qualifier. Profiles control bean registration. Qualifiers control which already-registered bean gets injected.
Prefer Constructor Injection for Clarity
Constructor injection makes ambiguity visible immediately and keeps dependencies immutable.
If wiring is wrong, the application fails at startup instead of hiding problems in mutable fields. That is a strong default for most Spring Boot services.
Common Pitfalls
- Expecting Spring to choose between multiple interface implementations without explicit guidance.
- Using
@Primarywhen the correct implementation actually depends on runtime context. - Relying on implicit bean names and breaking qualifiers during refactoring.
- Switching to field injection instead of fixing the wiring design clearly.
- Forgetting that profiles and conditions change which beans exist at all.
Summary
- Multiple implementations make type-based autowiring ambiguous by design.
- Use
@Qualifierwhen one class needs one specific bean. - Use
@Primarywhen one implementation should be the default. - Inject a collection when runtime strategy selection is part of the design.
- Prefer constructor injection so wiring errors fail early and clearly.
Related reading
- Spring Boot can't autowire ConfigurationProperties
- Spring Boot Inherit application.properties from dependency
- spring boot test unable to inject TestRestTemplate and MockMvc
- Spring @Component versus @Bean
- Spring Boot bean conditional on ConfigurationProperties value
- Spring Boot Cannot access REST Controller on localhost 404
- Spring get all Beans of certain interface AND type
- Spring injects dependencies in constructor without Autowired annotation

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.