Spring循环依赖面试中也会被常常问到。但是它的整个过程很多人都不知道,什么叫循环依赖呢。多个Bean之间相互依赖,形成一个闭环。如下图(A,B,C分别为Spring容器中3个Bean)就能很好的描述。(PS必须保证默认的Bean都是单例的循环依赖才成立)。

上面是对Spring循环依赖的简单解释,下图是Spring官网说明。

上图中重点翻译就是:循环依赖不支持构造方法的注入,使用构造方法注入会抛出BeanCurrentlyInCreationException异常 。Spring不推荐构造注入,只支持setter注入。

Spring是怎么支持和解决循环依赖的呢?

它目前解决的方案是靠自身容器中的3个Map来解决的,也称为三级缓存,如下图:

第一级缓存(也叫单例池)singleObjects:存放已经经历完整生命周期的Bean对象。

第二级缓存:earlySingletonObjects,存放早期暴漏的Bean对象,Bean周期未结束(属性未完全填充)。

第三级缓存:singletonFactories,存放可以生成Bean的工厂。

那么下面我们就通过源码来说明Spring是如何通过上面三级缓存来解决循环依赖的,我们就用2个对象来演示和理解循环依赖。

1:A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B。

2:B实例化的时候发现需要A,于是B先查一级缓存,没有再查二级缓存,还是没有,再查三级缓存,找到了A,然后把三级缓存里面的A放到二级缓存里面,并删除三级缓存里面的A。

3:B顺利完成初始化,将自己放到一级缓存里面(此时B里面的A依然是创建中的状态)然后接着回来创建A,此时B已经创建结束,直接从一级缓存里面拿B,并将A自己放到一级缓存里面。

源码分析主要关注如下方法的流程:

1:调用doCreateBean()方法,想要获取a ,于是调用getSingleton()方法从缓存中获取a 。

2:getSingleton()方法从一级缓存中找,没有找到返回null。

3:如果getSingleton()方法中获取到的a为null ,于是走对应的逻辑处理,调用getSingleton的重载的方法(参数为ObjectFactory)。

4:在getSingleton()中将a添加到一个集合中,用于标记a正在创建中,然后调用匿名内部类的creatBean方法。

5:进入AbstractAutowireCapableBeanFactory的doCreateBean,创建出a的实例然后将a添加到三级缓存中。

6:对a进行属性的填充,此时检测到a依赖于b,于是开始找b 。

7:找b的时候调用doGetBean()方法和上面创建a的过程一样,到缓存中找b,没有则创建,然后给b填充属性。

8:此时b依赖于a,调用getSingleton获取a,依次从一级,二级,三级缓存中找,此时从三级缓存中获取a的创建工厂,通过创建工厂获取到singeltonObject,此时这个singletonObject指向的就是上面的doCreateBean方法中获取的实例化的a。

9:这样b就获取到了a的依赖,于是b顺利完成了实例化,并将a从三级缓存移到二级缓存中。

10:随后a继续属性填充的工作,此时也获取了b,然后a也就完成了创建,回到getSingleton方法中继续执行,将a从二级缓存移动到一级缓存。

具体为什么用三级缓存不用二级缓存去解决,后面章节分析,欢迎转发,评论,点赞

微信公众号搜索:程序员xiaozhang 。如果遇到Spring的问题也可以私信我 能帮忙解决的尽量解决。