在 Spring 项目中,当你这样声明:
@Resource
private List<IGoodsActuator> goodsActuators;
这个 goodsActuators 字段的初始化(即注入)发生在 Spring 容器创建该 Bean 的依赖注入阶段(population phase),具体来说是在 Bean 实例化之后、初始化回调(如 @PostConstruct)之前。
📌 详细时机说明(Bean 生命周期视角)
假设你有一个被 Spring 管理的组件类:
@Service
public class GoodsService {@Resourceprivate List<IGoodsActuator> goodsActuators;@PostConstructpublic void init() {// 此时 goodsActuators 已经被注入System.out.println("Size: " + goodsActuators.size());}
}
Spring 创建 GoodsService Bean 的流程如下:
- 实例化:调用
GoodsService的构造函数,创建对象(此时字段仍为 null)。 - 依赖注入(DI):
- Spring 扫描所有字段和 setter 方法;
- 发现
@Resource private List<IGoodsActuator> goodsActuators; - 查找容器中所有类型为
IGoodsActuator的 Bean(包括其实现类,如DiscountActuator,StockActuator等); - 将这些 Bean 组装成一个
List,并注入到goodsActuators字段中。
- 初始化回调:
- 调用
@PostConstruct标注的方法(如init()); - 此时
goodsActuators已经完成注入,可以安全使用。
- 调用
✅ 因此:
goodsActuators在@PostConstruct方法执行前就已经初始化完毕。
🔍 关键行为细节
1. 自动收集所有匹配的 Bean
Spring 对 List<T> 类型的注入有特殊处理:
- 不管你用的是
@Resource还是@Autowired, - 只要字段类型是
List<SomeInterface>, - Spring 就会自动将容器中 所有实现了
SomeInterface的 Bean 注入到该列表中。
⚠️ 注意:虽然
@Resource按 JSR-250 规范本应“按名称注入”,但 Spring 对集合类型(List/Map)做了扩展,此时它会忽略名称,转而按类型收集所有匹配 Bean。
2. 空列表而非 null
- 如果没有
IGoodsActuator的实现类被注册为 Bean,goodsActuators会被注入为一个 空的ArrayList,不会是null。 - 这避免了空指针异常(NPE),是 Spring 的安全设计。
3. 顺序可控
- 默认顺序是 Bean 的注册顺序;
- 可通过
@Order注解或实现Ordered接口控制执行顺序:@Component @Order(1) public class FirstActuator implements IGoodsActuator { ... }
✅ 验证示例
@Component
public class A implements IGoodsActuator { }@Component
public class B implements IGoodsActuator { }@Service
public class MyService {@Resourceprivate List<IGoodsActuator> goodsActuators; // 包含 A 和 B@PostConstructpublic void check() {// 输出:2System.out.println(goodsActuators.size());}
}
🆚 与 @Autowired 的区别?
对于 List<T> 注入,在 Spring 中 @Resource 和 @Autowired 行为几乎一致:
@Autowired
private List<IGoodsActuator> goodsActuators; // 效果相同
因为 Spring 在解析集合类型时,会统一走“按类型收集所有 Bean”的逻辑,不再区分注解语义。
✅ 总结
| 问题 | 答案 |
|---|---|
| 何时初始化? | 在当前 Bean 的 依赖注入阶段,早于 @PostConstruct。 |
| 注入内容? | 容器中所有 IGoodsActuator 类型的 Bean(实现类)。 |
| 为空怎么办? | 注入空 List,永不为 null。 |
| 顺序是否确定? | 默认按注册顺序,可用 @Order 控制。 |
@Resource 是否按名注入? |
❌ 对 List<T>,Spring 忽略名称,按类型自动收集。 |
💡 最佳实践:在
@PostConstruct或业务方法中使用goodsActuators是安全的,无需判空(除非业务逻辑需要)。