1. 概述

本文将探讨如何在 Spring 中通过泛型参数实现 Bean 的自动注入(Autowiring)。这在处理多种实现类时尤其有用,能让我们更精准地控制依赖注入的行为,避免手动添加大量注解或配置。

核心价值:✅ 减少样板代码提升类型安全性让注入逻辑更清晰


2. Spring 3.2 中的泛型自动注入

Spring 3.2 开始,就已支持泛型类型的自动注入。这意味着你可以直接注入 List<T>Map<String, T> 等结构,Spring 会自动匹配符合泛型约束的 Bean。

举个例子,我们有一个抽象类 Vehicle 和一个具体实现类 Car

public abstract class Vehicle {
    private String name;
    private String manufacturer;

    // 构造方法、getter、setter 等省略
}
public class Car extends Vehicle {
    private String engineType;

    // 构造方法、getter、setter 等省略
}

现在,假设我们需要在一个处理器中注入所有 Vehicle 类型的 Bean:

@Autowired
private List<Vehicle> vehicles;

⚠️ 注意:Spring 会自动把容器中所有 Vehicle 类型的 Bean 都注入到这个列表中 —— 无论你是用 @Bean@Component 还是 XML 配置的。

使用自定义 Qualifier 精确筛选

如果你只想注入特定的 Vehicle 实例(比如仅限汽车),可以使用 @Qualifier 自定义注解来打标签。

定义一个 @CarQualifier 注解:

@Target({
    ElementType.FIELD, 
    ElementType.METHOD,
    ElementType.TYPE, 
    ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface CarQualifier {
}

然后在字段上使用它:

@Autowired
@CarQualifier
private List<Vehicle> vehicles;

接着,在配置类中为需要的 Bean 添加该注解:

@Configuration
public class CustomConfiguration {
    @Bean
    @CarQualifier
    public Car getMercedes() {
        return new Car("E280", "Mercedes", "Diesel");
    }

    @Bean
    public Motorcycle getHarley() {
        return new Motorcycle("Street 750", "Harley-Davidson", true);
    }
}

✅ 结果:只有被 @CarQualifier 标记的 Car 实例会被注入到 vehicles 列表中,Motorcycle 虽然也是 Vehicle,但不会被包含。


3. Spring 4.0 起:直接用泛型作为“隐式 Qualifier”

到了 Spring 4.0,事情变得更简单了。

假设我们还有一个 Motorcycle 类:

public class Motorcycle extends Vehicle {
    private boolean twoWheeler;

    // getter、setter 等省略
}

如果我们现在只想注入 Car 类型的 Bean,而不要 Motorcycle,可以直接写:

@Autowired
private List<Car> vehicles;

Spring 4.0+ 会自动识别泛型类型 Car 作为筛选条件,无需再加 @Qualifier

这背后的机制是:Spring 使用泛型信息去匹配 Bean 的实际类型,只要 Bean 是 Car 或其子类,就会被注入。

❌ 而在 Spring 4.0 之前,这种写法会导致 NoUniqueBeanDefinitionException 或注入不准确,因为泛型擦除导致无法判断具体类型。

💡 小结:

  • Spring 3.2:支持泛型注入,但多实现时需靠 @Qualifier 区分
  • Spring 4.0+:泛型本身即可作为“类型过滤器”,简单粗暴有效

4. ResolvableType:泛型注入的核心支撑

这一切之所以能实现,离不开 Spring 内部的 ResolvableType 类。

ResolvableType 是 Spring 4.0 引入的一个工具类,用于在运行时解析泛型类型信息,绕过 Java 的泛型擦除限制。

它能提取字段、方法参数、返回值等位置的完整类型信息,包括:

  • 超类
  • 接口
  • 泛型参数
  • 最终解析为 Class 对象

示例代码

假设我们有如下字段:

@Autowired
private List<Vehicle> vehicles;

可以通过反射 + ResolvableType 获取其泛型信息:

ResolvableType vehiclesType = ResolvableType.forField(getClass().getDeclaredField("vehicles"));
System.out.println(vehiclesType); // 输出: java.util.List<com.example.model.Vehicle>

ResolvableType genericType = vehiclesType.getGeneric();
System.out.println(genericType);  // 输出: com.example.model.Vehicle

Class<?> resolvedClass = genericType.resolve();
System.out.println(resolvedClass); // 输出: class com.example.model.Vehicle

输出结果:

java.util.List<com.example.model.Vehicle>
com.example.model.Vehicle
class com.example.model.Vehicle

📌 这就是 Spring 能“看懂” List<Vehicle> 中的 Vehicle 的原因 —— 不再依赖注解,而是直接解析泛型。


5. 总结

泛型自动注入是 Spring DI 中一个低调但极其实用的功能:

  • Spring 3.2+ 支持泛型注入,配合 @Qualifier 可实现精细控制
  • Spring 4.0+ 更进一步,允许直接用泛型类型作为隐式筛选条件,无需额外注解
  • ✅ 背后依赖 ResolvableType 解决泛型擦除问题,类型安全且高效

🚀 实际应用场景建议:

  • 多策略模式(如 List<PaymentStrategy>
  • 事件处理器列表(List<EventHandler<T>>
  • 插件式架构中的服务发现

代码示例已上传至 GitHub:https://github.com/example/spring-generic-autowire-demo


原始标题:Spring Autowiring of Generic Types