开发过程中有这样一个场景,2个bean初始化逻辑中有依赖关系,需要控制二者的初始化顺序。实现方式可以有多种,本文结合目前对春天的理解,尝试列出几种思路。
<>强场景强>
假设A、B两个bean都需要在初始化的时候从本地磁盘读取文件,其中B加载的文件,依赖一个中加载的全局配置文件中配置的路径,所以需要一个先于B初始化,此外一个中的配置改变后也需要触发B的重新加载逻辑,所以A、B需要注入彼此。
对于下面的模型,问题简化为:我们需要initA()先于initB()得到执行。
@ service 公共类{ @ autowired 私人B B; 公众(){ system . out。println(“构造”); } @PostConstruct 公共空间init () { initA (); } 私人空间initA () { system . out。println (“init”); } } @ service 公共类B { @ autowired 私人的; 公共B () { system . out。println (" B构造”); } @PostConstruct 公共空间init () { initB (); } 私人空间initB () { system . out。println (“B init”); } } >之前<强>方案一:立旗强>
我们可以在业务层自己控制A, B的初始化顺序,在一个中设置一个”是否初始化的“标记,B初始化前检测一个是否得以初始化,如果没有则调用一个的初始化方法,所谓的check-and-act。对于上述模型,实现如下:
@ service 公共类{ 私人静态不稳定的布尔值初始化; @ autowired 私人B B; 公众(){ system . out。println(“构造”); } @PostConstruct 公共空间init () { initA (); } 公共布尔isInitialized () { 返回初始化; } 公共空间initA () { 如果(! isInitialized ()) { system . out。println (“init”); } 初始化=true; } } @ service 公共类B { @ autowired 私人的; 公共B () { system . out。println (" B构造”); } @PostConstruct 公共空间init () { initB (); } 私人空间initB () { 如果(! a.isInitialized ()) { a.initA (); } system . out。println (“B init”); } >之前执行效果:
构建
B构建
一个init
B init
这种立旗的方法好处是可以做到延迟初始化,但是如果类似逻辑很多的话代码中到处充斥着类似代码,不优雅,所以考虑是否框架本身就可以满足我们的需要。
<强>方案二:使用取决于强>
中春天的取决于注解可以保证被依赖的豆先于当前bean被容器创建,但是如果不理解春天中豆加载过程会对取决于有误解,自己也确实踩过坑。对于上述模型,如果在B上加上注解@DependsOn ({a}),得到的执行结果是:
构建
B构建
B init
一个init
在这里问题的关键是:豆属性的注入是在初始化方法调用之前。
//代码位置:AbstractAutowireCapableBeanFactory.doCreateBean//填充bean的各个属性,包括依赖注入 populateBean (beanName mbd instanceWrapper); 如果(exposedObject !=null) {//调用初始化方法,如果是InitializingBean则先调用afterPropertiesSet然后调用自定义的init方法方法 exposedObject=initializeBean (beanName exposedObject mbd); }结合本例,发生的实际情况是,因为出现了循环依赖,一个依赖B,加载B, B依赖,所以得到了一个提前暴露的,然后调用B的初始化方法,接着回到一个的初始化方法。具体源码分析过程如下:
ApplicationContext在刷新过程中的最后会加载所有的没有懒惰的单例。
本例中,先加载的bean,最终通过无参构造器构造,然后,继续属性填充(populateBean),发现需要注入bean B所以转而加载bean B(递归调用getBean())。此时发现bean B需要取决于(“A”),在保存依赖关系(为了防止循环取决于)后,调用getBean (“A”),此时会得到提前暴露的bean,所以继续B的加载,流程为:初始化策略构造实例→属性填充(同样会注入提前暴露的bean)→调用初始化方法。
详解春天中如何控制2个bean中的初始化顺序