In Spring, it’s common to have multiple beans of the same type. When you do, you may encounter issues with @Autowired or dependency injection because Spring doesn’t know which bean to inject. Here are several ways to handle multiple beans of the same type in Spring:
1. Using @Qualifier
-
You can use
@Qualifierwith@Autowiredto specify which bean you want to inject by its name.123456789101112131415@Componentpublic class MyServiceOne implements MyService { /* ... */ }@Componentpublic class MyServiceTwo implements MyService { /* ... */ }@Servicepublic class MyClientService {private final MyService myService;@Autowiredpublic MyClientService(@Qualifier("myServiceOne") MyService myService) {this.myService = myService;}}
Here, @Qualifier("myServiceOne") specifies that myServiceOne bean should be injected into myService.
2. Using @Primary
-
If you want one bean to be injected by default, you can use the
@Primaryannotation. Spring will inject the primary bean when no@Qualifieris specified.123456789101112@Component@Primarypublic class MyPrimaryService implements MyService { /* ... */ }@Componentpublic class MySecondaryService implements MyService { /* ... */ }@Servicepublic class MyClientService {@Autowiredprivate MyService myService; // Will inject MyPrimaryService}
In this example, MyPrimaryService is marked with @Primary, so it’s used as the default bean unless another specific one is requested.
3. Injecting All Beans of a Type with @Autowired and @Qualifier
-
You can inject a collection of all beans of a specific type using
@Autowiredon aListorMap. This approach is helpful if you want to access all beans of a certain type.12345@Servicepublic class MyClientService {@Autowiredprivate List<MyService> myServices; // All MyService beans will be injected here}
Alternatively, you can inject a map with bean names as keys and the beans as values:
|
1 2 3 4 5 |
@Service public class MyClientService { @Autowired private Map<String, MyService> myServicesMap; // All MyService beans injected with their names } |
4. Using Custom Qualifiers
-
You can create custom qualifiers to make the code more readable and intuitive, especially when there are many beans of the same type.
123456789101112131415@Qualifier@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })public @interface MyServiceOne {}@Component@MyServiceOnepublic class MyServiceOneImpl implements MyService { /* ... */ }@Servicepublic class MyClientService {@Autowired@MyServiceOneprivate MyService myService; // Will inject MyServiceOneImpl}
5. Using @Resource
-
You can use
@Resourceto specify the bean by its name.@Resourceworks similarly to@Autowiredwith@Qualifier, but it’s part of Java’sjavax.annotationpackage.12345@Servicepublic class MyClientService {@Resource(name = "myServiceOne")private MyService myService; // Injects the myServiceOne bean}
6. Using Conditional Beans with @Conditional
-
Sometimes, you only want one of the beans to be instantiated based on certain conditions. You can use
@Conditionalwith a custom condition or Spring’s built-in conditions to create conditional beans.1234567@Component@Conditional(MyCustomCondition.class)public class ConditionalServiceOne implements MyService { /* ... */ }@Component@ConditionalOnProperty(name = "myapp.feature.enabled", havingValue = "true")public class ConditionalServiceTwo implements MyService { /* ... */ }
In this example, ConditionalServiceOne or ConditionalServiceTwo beans will only be instantiated if certain conditions are met.
7. Using Profiles
-
If different beans should be active in different environments, you can annotate them with
@Profile.12345678910111213@Component@Profile("dev")public class DevService implements MyService { /* ... */ }@Component@Profile("prod")public class ProdService implements MyService { /* ... */ }@Servicepublic class MyClientService {@Autowiredprivate MyService myService; // Will inject either DevService or ProdService based on active profile}
Here, only one of the beans will be loaded depending on the active Spring profile (e.g., dev or prod).
Choosing the Right Strategy
The best approach depends on your needs:
- Use
@Primaryfor a single default implementation. - Use
@Qualifieror custom qualifiers to specify a particular bean. - Use
@Profilefor environment-specific beans. - Use
@Conditionalfor beans that should only be created under specific conditions.