Spring Bean 初始化顺序与依赖优先原则解析

作者:技术拾光

时间:2026-07-12

浏览:410

SpringBean初始化遵循依赖优先原则,先实例化无依赖或依赖较少的Bean,再逐步处理复杂依赖关系,通过依赖注入和循环依赖的妥善解决,确保getBean()时所有对象均已准备就绪,从而保障容器启动的稳定性和有序性。

文章目录

这个问题切中了许多开发者在初学 Spring 时容易陷入的误区:以为 getBean() 在何处调用,Bean 便在何处初始化。实际上,Spring 容器在启动阶段就会完成所有非懒加载单例 Bean 的创建与初始化,不会等到伸手去取的那一刻。因此,A 的构造函数最先执行——根本原因在于 A 是 B 和 C 的共同依赖,Spring 严格遵循“依赖优先”原则,在初始化 B 和 C 之前,必须确保 A 已经准备就绪。

这一机制背后,是 Spring IoC 容器中一套严谨的依赖图驱动的预初始化逻辑。以您给出的示例为例:

  • A、B、C 均为 @Component 标注的单例 Bean,默认非懒加载;
  • B 和 C 都通过 @Autowired setter 方法依赖 A(字段注入同理);
  • 当执行 new AnnotationConfigApplicationContext(LegendConfig.class) 时,Spring 启动流程立即触发完整的 Bean 生命周期管理。

核心执行逻辑(简化版)

  1. 扫描与注册:@ComponentScan 发现 A、B、C,将其注册到 BeanDefinitionRegistry;
  2. 依赖分析:Spring 构建依赖关系图——B → A,C → A,识别出 A 为被依赖方,B 和 C 为依赖方;
  3. 按需前置初始化:根据“依赖优先”原则,容器必须先完全初始化 A(包括构造、属性填充、初始化回调),才能安全地注入到 B 和 C 中;
  4. 统一初始化调度:所有非懒加载单例 Bean 在 refresh() 阶段集中创建,顺序如下:
    • 先实例化并初始化 A(A 构造函数执行);
    • 再实例化 B(B 构造函数执行),随后执行 setA() 注入;
    • 接着实例化 C(C 构造函数执行),再执行 setA() 注入。

注意:getBean(B.class) 仅仅是从已初始化完成的一级缓存中取出 B 实例,不会触发新建流程——这就是为什么输出中 “I am A constructor!” 永远排在第一位。

补充验证:构造注入 vs 字段/Setter 注入

若将依赖改为构造注入,顺序逻辑将更加直观:

@Component
class B {
    private final A a;
    public B(A a) { // 构造时强制依赖 A
        System.out.println("I am B constructor!");
        this.a = a;
    }
}

在这种情况下,Spring 会在 B 实例化之前确保 A 已完成整个生命周期(构造 + 初始化),否则无法调用 B 的构造函数——这正是 Spring 保证依赖可用性的底层契约。

关键注意事项

  • @Order 对 Bean 加载顺序无效:它仅影响 BeanPostProcessor、Advice 或集合注入时的排序,不能控制 Bean 创建先后;
  • @DependsOn 可以显式声明无直接引用的逻辑依赖(例如 @DependsOn("databaseInitializer")),但会绕过依赖图自动推导,需谨慎使用;
  • 循环依赖仅对单例 + Setter/字段注入场景可解(借助三级缓存),构造注入或原型 Bean 会直接抛出 BeanCurrentlyInCreationException;
  • 若需要严格控制初始化时机(例如某个 Bean 必须在所有其他 Bean 之前运行),推荐实现 ApplicationRunner 或 CommandLineRunner,而非强行干预 IoC 初始化顺序。

总结

Spring 的 Bean 初始化,本质上是声明式依赖驱动的编排过程,而非命令式的调用链。理解 getBean() 是“取”而非“造”,是掌握 Spring 生命周期的关键前提。只要记住这一条:

容器启动即完成非懒加载单例的全量初始化;依赖方永远晚于被依赖方;getBean() 仅仅是缓存访问操作。

这一原则贯穿 Spring Boot 自动配置、条件化加载以及各类扩展点设计,是构建高可靠性 Spring 应用的基石。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章