一、总说循环依赖描述及解决方案
描述:A对象中有b属性,B对象中有a属性,此时A、B两个对象相互引用,可能会出现循环依赖问题
解决方案:若出现循环依赖问题,可以采用三级缓存来解决此问题
二、造成循环依赖过程
1、A对象实例化,b属性设置默认值
2、A对象初始化,给b填充属性,从容器中寻找B对象
如果找到B对象,直接返回赋值即可
如果找不到B对象,创建B对象
3、B对象实例化,a属性设置默认属性
4、B对象初始化,给a填充属性,从容器中寻找A对象,此时A对象还没有初始化结束,形成闭环(循环依赖)
分析:
此时图中为一个闭环操作,及循环依赖,若不想出现这种场景,则需要在创建A对象这个步骤中保证容器中有A对象的存在
解决:
在Spring中对象的创建过程分为实例化和初始化,实例化但未初始化的对象是可以被其他对象引用的
这时,只要将实例化但未初始化的对象提前暴露,让其他对象可以进行引用,就完成了循环依赖的解环操作
提前暴露的对象放到一、二、三级缓存中
三、三级缓存
如果发生循环依赖的对象,不需要代理的话,只需要二级缓存足矣解决所有问题。但是当存在代理之后就无法解决了,必须使用三级缓存来解决
1、beanName和lamda表达式放到了三级缓存中,bean没有放到任何一级缓存中
2、每次找缓存优先从一级-->二级-->三级,在根据beanName去寻找对象时,可以在三级缓存中找到lambda表达式。通过singletonFactory.getObject()获取到对象放到二级缓存中
3、在二级缓存中存储的对象实例化完成但未初始化(A对象)
4、B对象拿到了半成品A对象,B对象就可以初始化成功,紧接着A对象也可以拿到B对象,A对象也就初始化成功了
三级缓存中并不是严格的从三级到二级到一级,这样的一个对象转化顺序,有可能在三级和一级中有对应,也有可能在一二三级中都有对象