Two Advanced Techniques to Avoid Overusing @Qualifier for Multiple Bean Injection in Spring
The article explains how to replace repetitive @Qualifier annotations in Spring by using generic‑type based injection and custom qualifier annotations, providing concrete code examples and showing how Spring resolves beans without explicit qualifiers.
When a Spring container holds multiple beans of the same type, developers typically use @Qualifier to specify which bean to inject. The article first shows the classic approach with a simple example:
public interface DAO {}
@Component
public class A implements DAO {}
@Component
public class B implements DAO {}
@Service
public class Service {
@Autowired
@Qualifier("a")
private DAO dao;
}Beyond @Qualifier, the author introduces two advanced injection strategies.
1. Generic‑type based injection
By defining beans with generic type parameters, Spring can infer the correct bean from the field’s generic type, eliminating the need for @Qualifier. Example implementation:
public abstract class Store<T> {
protected T value;
public Store(T value) { this.value = value; }
}
@Component
public class StringStore extends Store<String> {
public StringStore(String value) { super(value); }
}
@Component
public class IntegerStore extends Store<Integer> {
public IntegerStore(Integer value) { super(value); }
}
@Component
public class Service {
@Resource
private Store<String> stringStore;
@Resource
private Store<Integer> integerStore;
}
@Autowired
private List<Store<String>> list; // collection injection also worksIn this setup, the Service component receives the appropriate Store implementation based solely on the generic type, and no @Qualifier annotation is required.
2. Custom qualifier annotations
Spring also allows developers to define their own qualifier annotations. Two custom annotations are created:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface PackInject {}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface CommonInject {}To make Spring recognise these annotations, a CustomAutowireConfigurer (a BeanFactoryPostProcessor) is registered:
@Configuration
public class AppConfig {
@Bean
public CustomAutowireConfigurer customAutowireConfigurer() {
CustomAutowireConfigurer cfg = new CustomAutowireConfigurer();
cfg.setCustomQualifierTypes(Set.of(PackInject.class, CommonInject.class));
return cfg;
}
}Beans are then annotated with the custom qualifiers:
public interface DAO {}
@PackInject
public class A implements DAO {}
@CommonInject
public class B implements DAO {}And injection points declare the desired qualifier:
@Autowired
@PackInject
private DAO adao;
@Autowired
@CommonInject
private DAO bdao;Both adao and bdao are correctly injected, demonstrating that custom annotations function equivalently to @Qualifier but provide clearer semantics and avoid cluttering the code with repetitive qualifier strings.
The article concludes that these two techniques—generic‑type based injection and custom qualifier annotations—offer cleaner, more maintainable ways to handle multiple bean implementations in Spring, reducing reliance on the verbose @Qualifier pattern.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
