This error means Spring couldn’t decide which implementation of an interface to inject because you have multiple candidates and didn’t specify a preference.
Here’s why this happens and how to fix it:
-
Multiple Implementations of an Interface: You’ve likely defined two or more classes that implement the same interface, and Spring is trying to inject an instance of that interface into another component.
- Diagnosis: Run
mvn dependency:treeorgradle dependenciesto see your project’s dependency structure. Look for multiple classes implementing the same interface. - Fix: This isn’t a "fix" in itself, but the reason for the error. You need to tell Spring which one to use.
- Diagnosis: Run
-
Missing
@PrimaryAnnotation: When Spring finds multiple beans of the same type, it needs a hint. The@Primaryannotation is the most common way to give Spring that hint.- Diagnosis: Check your bean definitions. You’ll see multiple classes implementing the same interface, none of which are marked with
@Primary. - Fix: Add
@Primaryto the bean definition of the implementation you want Spring to prefer. For example, if you haveMyServiceinterface and implementationsDatabaseServiceandCacheService, mark the one you want by default:@Service @Primary public class DatabaseService implements MyService { // ... } - Why it works:
@Primarytells Spring, "When there’s ambiguity, pick this one first."
- Diagnosis: Check your bean definitions. You’ll see multiple classes implementing the same interface, none of which are marked with
-
Using
@QualifierIncorrectly: Another way to disambiguate is with@Qualifier, but it’s often misused when@Primaryis more appropriate for a default.- Diagnosis: You might have
@Autowired MyService myService;and then in another class,@Autowired @Qualifier("DatabaseService") MyService myService;. This is fine if you always wantDatabaseServicein that specific context. However, if you wantDatabaseServiceto be the default everywhere unless explicitly overridden,@Primaryis the correct tool. - Fix: If you want a default service, apply
@Primaryto that service’s bean definition. If you only want to specify a particular implementation in a specific injection point, use@Qualifierthere.// In the bean definition @Service("databaseService") // or just @Service if no specific name needed public class DatabaseService implements MyService { ... } @Service public class CacheService implements MyService { ... } // In the class that needs injection @Autowired private MyService myService; // This would fail without @Primary // To inject the default (if DatabaseService is @Primary) @Autowired private MyService defaultService; // Injects DatabaseService // To inject a specific one when there's no @Primary, or to override @Primary @Autowired @Qualifier("cacheService") // Or @Qualifier("CacheService") depending on bean name private MyService specificService; // Injects CacheService - Why it works:
@Qualifierallows you to target a bean by its name (either the default name derived from the class name or a name explicitly given via@Service("beanName")or@Qualifier("beanName")on the injection point).
- Diagnosis: You might have
-
Spring Boot Auto-configuration Conflicts: Sometimes, third-party libraries or Spring Boot’s auto-configuration might introduce beans that conflict with your own, leading to multiple implementations of an interface.
- Diagnosis: Use
grepor your IDE’s search to find all classes implementing the problematic interface. Identify which ones are from your project and which are from dependencies. - Fix: If a dependency is providing an unwanted implementation, you can often exclude it from the dependency management or disable its auto-configuration. For example, if a
DataSourceAutoConfigurationis causing issues:@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } - Why it works: This prevents Spring from even creating the conflicting bean from the external library.
- Diagnosis: Use
-
Incorrect Configuration Properties: Certain configuration properties can implicitly enable or disable beans, leading to unexpected multiple implementations being available.
- Diagnosis: Review your
application.propertiesorapplication.ymlfile. Look for properties related to the interface or its implementations. For instance, if you’re dealing with multipleMessageSourcebeans, properties likespring.messages.basenamemight be relevant. - Fix: Adjust the configuration properties to ensure only one desired bean is activated. Often, this involves setting a specific property that targets the bean you want to use or disabling others. For example, if you have two
RestTemplateconfigurations and want to use the one configured programmatically:
(Note: This is a simplified example; the exact property depends on the specific auto-configuration.)# Ensure auto-configured RestTemplate is not preferred if you have a custom one spring.mvc.throw-exception-if-no-handler-found=true - Why it works: Configuration properties are Spring’s primary mechanism for controlling auto-configuration and bean behavior.
- Diagnosis: Review your
-
Nested
@ComponentScanIssues: If you have multiple@ComponentScanannotations, especially with different base packages, you might accidentally scan directories that contain duplicate implementations of an interface.- Diagnosis: Examine all
@ComponentScanannotations in your application. Check the base packages they cover. - Fix: Consolidate your
@ComponentScanannotations or ensure they cover distinct, non-overlapping sets of packages. If you have a main application class with@SpringBootApplication(which includes@ComponentScan), you usually don’t need additional@ComponentScanannotations unless you’re explicitly trying to scan outside the default hierarchy.@SpringBootApplication(scanBasePackages = {"com.example.myapp.controllers", "com.example.myapp.services"}) public class MyApplication { ... } - Why it works: This ensures Spring only discovers the intended set of beans, preventing duplicate registrations.
- Diagnosis: Examine all
-
Spring Profiles: If different Spring profiles activate different implementations of the same interface, and you run the application without a profile or with multiple conflicting profiles, you might end up with ambiguity.
- Diagnosis: Check your profile-specific configuration files (e.g.,
application-dev.properties,application-prod.properties) for bean definitions or configurations that create implementations of the problematic interface. - Fix: Ensure that for any given active profile, only one implementation of the interface is registered. This might involve using
@ConditionalOnPropertyor@Profileannotations carefully, or providing a default implementation with@Primarythat is overridden by profile-specific beans.@Configuration public class ServiceConfig { @Bean @Primary public MyService defaultService() { return new DefaultServiceImpl(); } @Bean @Profile("prod") public MyService prodService() { return new ProdServiceImpl(); } } - Why it works:
@Profileensures that a bean is only created when the specified profile is active, controlling which implementation is available at runtime.
- Diagnosis: Check your profile-specific configuration files (e.g.,
After applying @Primary to your desired bean, you might encounter a NoSuchBeanDefinitionException if you try to inject a bean that no longer has a default and hasn’t been explicitly qualified.