You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring如何在运行时类型擦除时向泛型List<UnitMapping>注入对应实例?

Spring如何在泛型擦除下注入泛型列表?

这个问题问到点子上了——Java的泛型擦除确实会让运行时丢失具体类型信息,但Spring早就通过保留在字节码里的泛型元数据解决了这个问题,具体逻辑是这样的:

1. 泛型并没有被完全"擦除"

Java的泛型擦除只是在运行时把泛型参数替换成了Object(或者上界类型),但类的字节码中会保留泛型的签名信息(通过Signature属性)。Spring可以通过Java反射API(比如Field.getGenericType())获取到这些元数据,进而解析出泛型的实际类型参数。

2. Spring解析泛型字段的具体逻辑

当Spring扫描到MapUnitsService里的@Autowired private List<UnitMapping> unitMappings字段时:

  • 它会先获取这个字段的GenericType,得到一个ParameterizedType对象(代表带参数的泛型类型)
  • 调用getActualTypeArguments()方法,取出泛型的实际参数类型——也就是UnitMapping.class
  • 然后去Spring容器中查找所有类型为UnitMapping(或其子类/实现类)的Bean实例

3. 收集并注入符合条件的Bean

假设你有多个UnitMapping的实现类都被注册为Bean:

@Component
public class LengthUnitMapping implements UnitMapping { /* ... */ }

@Component
public class WeightUnitMapping implements UnitMapping { /* ... */ }

Spring会把这两个实例全部收集起来,注入到unitMappings列表中。如果需要控制列表的顺序,可以给Bean加上@Order注解,或者让Bean实现Ordered接口,默认情况下Spring会按Bean的名称字母顺序排序。

简单理解反射解析的核心代码

Spring内部大概会做类似这样的操作(简化版):

// 获取字段的泛型类型
Field field = MapUnitsService.class.getDeclaredField("unitMappings");
ParameterizedType genericType = (ParameterizedType) field.getGenericType();
// 取出泛型参数的实际类型
Class<?> targetType = (Class<?>) genericType.getActualTypeArguments()[0];
// 从容器中获取所有该类型的Bean
List<Object> beans = applicationContext.getBeansOfType(targetType).values().stream().collect(Collectors.toList());
// 注入到字段中
field.set(mapUnitsServiceInstance, beans);

总结一下:Spring并没有绕过泛型擦除,而是利用了Java字节码中保留的泛型元数据,通过反射解析出泛型参数的实际类型,从而精准找到需要注入的Bean集合。

内容的提问来源于stack exchange,提问作者rogergl

火山引擎 最新活动