使用泛型作为自动装配限定符 (Using Generics as Autowiring Qualifiers)
除了 @Qualifier 注解之外,你还可以使用 Java 泛型类型作为一种隐式的限定方式。例如,假设你有以下配置:
@Configuration
public class MyConfiguration {
@Bean
public StringStore stringStore() {
return new StringStore();
}
@Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
}@Configuration
class MyConfiguration {
@Bean
fun stringStore() = StringStore()
@Bean
fun integerStore() = IntegerStore()
}假设上述 Bean 实现了泛型接口(即 Store<String> 和 Store<Integer>),你可以对 Store 接口进行 @Autowired 注入,此时泛型将作为限定符使用,如下例所示:
@Autowired
private Store<String> s1; // 使用 <String> 限定,注入 stringStore bean
@Autowired
private Store<Integer> s2; // 使用 <Integer> 限定,注入 integerStore bean@Autowired
private lateinit var s1: Store<String> // 使用 <String> 限定,注入 stringStore bean
@Autowired
private lateinit var s2: Store<Integer> // 使用 <Integer> 限定,注入 integerStore bean泛型限定符也适用于自动装配列表(List)、Map 实例和数组。以下示例自动装配了一个泛型 List:
// 注入所有具有 <Integer> 泛型的 Store Bean
// Store<String> Bean 不会出现在此列表中
@Autowired
private List<Store<Integer>> s;// 注入所有具有 <Integer> 泛型的 Store Bean
// Store<String> Bean 不会出现在此列表中
@Autowired
private lateinit var s: List<Store<Integer>>补充教学 —— 泛型注入的“降维打击”
在 Spring 的早期版本中,泛型在注入时会被擦除(Type Erasure),导致如果你有多个不同泛型的同名类,Spring 会因为类型冲突而报错。但从 Spring 4.0 开始,Spring 增强了对泛型的感知能力。
1. 为什么它是“隐式限定符”? 在没有泛型支持前,如果你有两个 Store 实例,你必须配合 @Qualifier("stringStore") 来区分。 现在,你只需要写成 Store<String>,Spring 内部会提取出泛型参数,将其作为一个过滤条件。这比写字符串限定符更加类型安全,且支持 IDE 的重构和代码提示。
2. 典型的应用场景:通用 CRUD 模式 这是泛型注入最强大的地方。你可以定义一个通用的 BaseService<T>:
public class BaseService<T> {
@Autowired
protected BaseMapper<T> mapper; // 自动根据子类的泛型注入对应的 Mapper
}
@Service
public class UserService extends BaseService<User> {
// 这里的 mapper 会自动被注入为 BaseMapper<User>
}这种模式可以极大地减少重复的注入代码。
3. 它是如何做到的? Spring 并不是真的绕过了 Java 的类型擦除,而是通过反射读取了类定义中的“签名”(Signature)元数据。这就是为什么它要求 Bean 的返回类型必须明确声明泛型信息。
- 注意:如果你在
@Bean方法里返回的是原始类型(Raw Type),泛型注入就会失效。
4. 集合注入的精准过滤 文档中提到的 List<Store<Integer>> 非常有用。设想你有一个插件系统,每个插件处理不同类型的数据:
@Autowired
private List<Processor<Image>> imageProcessors; // 只拿处理图片的插件Spring 会过滤掉 Processor<Video> 等其他不相关的插件,让你的业务代码非常干净。