先有鸡还是先有蛋,这是一个问题。
目录
1. 什么是循环依赖
你中有我,我中有你,就是循环依赖。举个例子,本文使用的项目中“yadang”与“xiawa”这两个bean就是循环依赖的(参考附录)。Class Adam中的Eve eve属性依赖Spring框架自动注入,同样Class Eve中的Adam adam属性也依赖于框架的自动注入。并且,Adam和Eve都是单例的。这种情况下,就构成了两个对象的循环依赖。
2. Spring针对循环依赖的解决方案
二话不说,先来一张图描述Spring对于循环依赖的解决方案。
如果您是按照本系列文章的序号依次读完再到这里的,那么根据上面这张图你就已经能看透Spring框架处理循环依赖的方式了,强烈建议您不要看下文,自己根据上图和写个demo debug分析分析印象更深。
如果您仅仅想知道Spring是如何做到的,那我们就开始吧。
2.1 亚当的登场
假设目前“亚当”和“夏娃”这两个bean都还未曾创建,现在流程走到亚当的创建流程(蓝色流程)。因为亚当创建之前不曾有亚当创建出来被容器托管,故流程会很顺利的走到createBean。在createBean之前,会通过beforeSingletonCreation在bean工厂的singletonsCurrentlyInCreation Set集合中添加亚当这个bean的beanName——“yadang”。
随后流程陷入doCreateBean方法中,首先通过createBeanInstance创建出亚当这个对象adamObj,请注意目前亚当它目前长这样:
adam:
eve : null
接着流程通过addSingletonFactory,如果在singletonObjects中没有找到“yadang”这个对象,那么就尝试在bean工厂的singletonFactories中进行如下步骤:
1.添加<yadang, singletonFactory>到中singletonFactories中,元素的key是亚当的beanName,value是创造该对象所用的bean工厂。
2.在registeredSingletons中添加“yadang”。
3.在earlySingletonObjects中移除key为“yadang”的对象(不存在也不会报错)。
到目前为止,bean工厂中各个缓存容器的值如下:
singletonObjects | null |
registeredSingletons |
"yadang" |
singletonFactories |
<yadang, factory> |
earlySingletonObjects |
null |
singletonsCurrentlyInCreation |
"yadang" |
亚当创建完成后,就需要通过populateBean对属性进行依赖注入,流程会陷入inject方法,最终通过doResolveDependency一路调用到getBean(“xiawa”)。这时流程就走到了夏娃的创建流程(粉色流程)。
2.2 夏娃的诞生
由于bean工厂中singletonObjects并未缓存有夏娃这个bean(beanName是“xiawa”)。那么夏娃的创建流程就和亚当的类似,它也会通过doCreateBean方法中createBeanInstance创建出夏娃