我们都知道,单例Bean初始化完成,要经历三步:
![](https://img-blog.csdnimg.cn/img_convert/4248aba671ad0352d483f552a6d4c1b9.png)
Bean初始化步骤
注入就发生在第二步,属性赋值,结合这个过程,Spring 通过三级缓存解决了循环依赖:
一级缓存 : Map<String,Object> singletonObjects,单例池,用于保存实例化、属性赋值(注入)、初始化完成的 bean 实例
二级缓存 : Map<String,Object> earlySingletonObjects,早期曝光对象,用于保存实例化完成的 bean 实例
三级缓存 : Map<String,ObjectFactory<?>> singletonFactories,早期曝光对象工厂,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。
![](https://img-blog.csdnimg.cn/img_convert/99c2b6840cff4e3228bc6f22b280c492.png)
三级缓存
我们来看一下三级缓存解决循环依赖的过程:
当 A、B 两个类发生循环依赖时:
![](https://img-blog.csdnimg.cn/img_convert/f529fe9e3a3c14eb004b5557f054d680.png)
A实例的初始化过程:
创建A实例,实例化的时候把A对象⼯⼚放⼊三级缓存,表示A开始实例化了,虽然我这个对象还不完整,但是先曝光出来让大家知道
![](https://img-blog.csdnimg.cn/img_convert/77fa1ee68619c1c4b74bc4716f488ca3.png)
A注⼊属性时,发现依赖B,此时B还没有被创建出来,所以去实例化B
同样,B注⼊属性时发现依赖A,它就会从缓存里找A对象。依次从⼀级到三级缓存查询A,从三级缓存通过对象⼯⼚拿到A,发现A虽然不太完善,但是存在,把A放⼊⼆级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入⼀级缓存。
![](https://img-blog.csdnimg.cn/img_convert/1c3d49b5445810a22752c6b27ec89d26.png)
接着A继续属性赋值,顺利从⼀级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除⼆级缓存中的A,同时把A放⼊⼀级缓存
最后,⼀级缓存中保存着实例化、初始化都完成的A、B对象
![](https://img-blog.csdnimg.cn/img_convert/a53359075af3af3d766f2313378a149d.png)
所以,我们就知道为什么Spring能解决setter注入的循环依赖了,因为实例化和属性赋值是分开的,所以里面有操作的空间。如果都是构造器注入的化,那么都得在实例化这一步完成注入,所以自然是无法支持了。