SpringBean初始化遵循依赖优先原则,先实例化无依赖或依赖较少的Bean,再逐步处理复杂依赖关系,通过依赖注入和循环依赖的妥善解决,确保getBean()时所有对象均已准备就绪,从而保障容器启动的稳定性和有序性。
这个问题切中了许多开发者在初学 Spring 时容易陷入的误区:以为 getBean() 在何处调用,Bean 便在何处初始化。实际上,Spring 容器在启动阶段就会完成所有非懒加载单例 Bean 的创建与初始化,不会等到伸手去取的那一刻。因此,A 的构造函数最先执行——根本原因在于 A 是 B 和 C 的共同依赖,Spring 严格遵循“依赖优先”原则,在初始化 B 和 C 之前,必须确保 A 已经准备就绪。
这一机制背后,是 Spring IoC 容器中一套严谨的依赖图驱动的预初始化逻辑。以您给出的示例为例:
长期稳定更新的攒劲资源: >>>点此立即查看<<<
@Component 标注的单例 Bean,默认非懒加载;@Autowired setter 方法依赖 A(字段注入同理);new AnnotationConfigApplicationContext(LegendConfig.class) 时,Spring 启动流程立即触发完整的 Bean 生命周期管理。@ComponentScan 发现 A、B、C,将其注册到 BeanDefinitionRegistry;refresh() 阶段集中创建,顺序如下:
setA() 注入;setA() 注入。注意:
getBean(B.class)仅仅是从已初始化完成的一级缓存中取出 B 实例,不会触发新建流程——这就是为什么输出中 “I am A constructor!” 永远排在第一位。
若将依赖改为构造注入,顺序逻辑将更加直观:
@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")),但会绕过依赖图自动推导,需谨慎使用;BeanCurrentlyInCreationException;ApplicationRunner 或 CommandLineRunner,而非强行干预 IoC 初始化顺序。Spring 的 Bean 初始化,本质上是声明式依赖驱动的编排过程,而非命令式的调用链。理解 getBean() 是“取”而非“造”,是掌握 Spring 生命周期的关键前提。只要记住这一条:
容器启动即完成非懒加载单例的全量初始化;依赖方永远晚于被依赖方;getBean() 仅仅是缓存访问操作。
这一原则贯穿 Spring Boot 自动配置、条件化加载以及各类扩展点设计,是构建高可靠性 Spring 应用的基石。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述