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
@Qualifier
with@Autowired
to 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
@Primary
annotation. Spring will inject the primary bean when no@Qualifier
is 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
@Autowired
on aList
orMap
. 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
@Resource
to specify the bean by its name.@Resource
works similarly to@Autowired
with@Qualifier
, but it’s part of Java’sjavax.annotation
package.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
@Conditional
with 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
@Primary
for a single default implementation. - Use
@Qualifier
or custom qualifiers to specify a particular bean. - Use
@Profile
for environment-specific beans. - Use
@Conditional
for beans that should only be created under specific conditions.