Spring容器启动时预创建所有非懒加载单例Bean,按依赖拓扑排序,无依赖的优先实例化,构造器先执行,随后通过setter方法注入依赖。获取Bean时仅从单例池返回引用,且所有初始化(包括属性赋值、Aware回调等)均在刷新阶段完成。
在Spring开发中,Bean的初始化和依赖注入顺序一直是开发者关注的重点。许多人会问:为什么依赖类构造函数总是先执行?关键在于,Spring容器启动时会预先创建并初始化所有非懒加载的单例Bean——这是容器生命周期机制决定的,与后续调用getBean()的顺序没有直接关系。
以你的示例为例,A、B、C三个类都使用@Component标注,默认是单例模式,且未启用@Lazy。当执行new AnnotationConfigApplicationContext(LegendConfig.class)时,Spring容器启动,进入预实例化阶段。容器会扫描所有Bean定义,然后按依赖拓扑排序——先创建那些没有依赖或依赖已经就绪的Bean。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
A()构造函数;B()构造函数,此时B实例已经存在,但其属性a尚未赋值;B.setA(a)——通过@Autowired setter注入,此时a已经是完全初始化好的A实例;setA()也在容器启动阶段完成,而不是等到调用getBean(C.class)时才触发。需要特别强调的是:applicationContext.getBean(B.class)并不会创建新实例,它只是从已构建好的单例池中返回引用。真正耗时的构造和注入过程,在上下文刷新(refresh())阶段已经全部完成。因此,你看到的输出顺序一定是:I am A constructor! → I am B constructor! → I am setA of B! → I am C constructor! → I am setA of C!。这印证了“构造先行、注入随后、获取即得”的全流程。
你可以通过以下配置验证这个行为:
@Configuration
@ComponentScan("com.spring.core.trialDI")
class LegendConfig {
@Bean(initMethod = "onInit")
public static class InitHook {
public void onInit() {
System.out.println(" All singleton beans initialized!");
}
}
}
BeanCurrentlyInCreationException;@Autowired方式)可以借助Spring的三级缓存机制解耦创建和注入,支持部分循环依赖场景;@Lazy注解,这样一来它的构造函数会在首次getBean()时才执行。总之,理解Spring的“启动期批量预创建 + 按需获取”模型,是掌握依赖注入时序逻辑的核心前提。记住,容器的初始化顺序基于依赖拓扑,而不是基于调用getBean()的顺序。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述