Spring循环依赖三级缓存
2022-04-19 11:08:58 0 举报
Spring循环依赖使用三级缓存问题总结。
作者其他创作
大纲/内容
半成品对象
缓存
没有返回值,只是对缓存的一些处理;if(一级缓存里没有的话){将该对象放到三级缓存从二级缓存中移除放到已注册bean单例集合中}
populateBean(...)填充bean
singletonFactory.getObject()(实际上在调用刚才的lambda表达式)
doGetBean(beanName)
通过三级缓存来解决循环依赖问题
可以使用lambda表达式
返回A成品对象
B对象在这里可以找到A对象的半成品
doCreateBean(...)
从容器中查找A对象
getSingleton(beanName)一级缓存没找到B
resolveValueIfNecessary(...)(这个属性需要处理的话就处理一下)
获取对象的BeanDefinition
填充B对象中的a属性
beanName = agetBean(beanName)
getSingleton(beanName)一级缓存没找到A
addSingletonFactory(beanName,()->getEarlyBeanReference(...))(又一个lambda表达式)
实例化完成初始化完成
resplveReference(...)
在一级缓存中查找:找不到A;对象是否在创建中:不是返回null
applyPropertyValues(...)(现在在给B对象里的A属性赋值)
没找到
创建B对象
其实是在回调getSingleton的lambda表达式
找不到
将beanName添加到已注册单例集合中
addSingleton()
***循环B结束****
填充属性
一级缓存没有A对象A对象是不是在创建中:true(和前两次不一样了)
初始化
在Spring中,对象是默认单例的,意味着容器里只有一个对象。现在面临的问题就是创建A就须有有B,创建B的时候又需要有A对象。这样就形成了一个闭环,现在就需要打破这个闭环。
无法解决循环依赖问题
三级缓存查找:存在,返回lambda表达式
bw.setPropertyValue()把B成品对象赋值给A对象的b属性
()->getEarlyBeanReference返回的是A的半成品对象
createBeanInstance
获取到当前属性类型:runtimeBeanRefence
为什么需要三级缓存?
bean = this.beanFactory.getBean(a)第三次getbean
找到了
构造器
调用init方法等相关操作
创建A对象
实例化B对象(a=null)
从容器中查找B对象
直接赋值
在一级缓存中查找:找不到B;对象是否在创建中:不是返回null
Spring循环依赖问题(三级缓存)
getBean
成品对象
在一级缓存中查找:找不到A
synchronized
在往二级缓存查找:(没有)
createBeanInstance(...)(创建A对象,实例化成功,但是还没有初始化)
时间点4:将B成品对象放入一级缓存将B从二级缓存删除将B从三级缓存删除
反射的方式来实例化对象
三级缓存对象的返回值,getObject()
放入二级缓存删掉三级缓存中数据
获取到当前属性名称:b
填充A对象的b属性
一级缓存找不到beanName
查找到半成品A后边不用在创建A对象了
逻辑相同
获取到A对象,赋值给B对象的a属性
getSingleton的lambda表达
createBean
doGetBean(beanName)beanName=a
class B引用 啊
applyPropertyValues(...)(现在在给A对象里的B属性赋值)
class A引用b
一级缓存找到B对象,
查找二级缓存(也没有)
时间点5:将A成品对象放入一级缓存将A从二级缓存删除将A从三级缓存删除
循环beanDefinitionNames,循环创建beanfor(String beanName beanNames)***循环A结束****
***循环B开始****
缓存半成品对象
bean = this.beanFactory.getBean(b)(和最开始的时候,getBean(a)的逻辑是一样的)
doGetBean
获取到当前属性名称:a
在查找一级缓存是否存在:(没有)
bw.setPropertyValue()把半成品A成品对象赋值给B对象的a属性
实例化A对象(b=null)
doCreateBean
把半成品对象缓存起来之后
A在这里找不到B半成品
doGetBean(beanName)beanName=b
获取到B的成品对象
set
循环beanDefinitionNames,循环创建beanfor(String beanName beanNames)***循环A开始****
DefaultListableBeanFactory.classpreInstantiateSingletons()
时间点1:把A的信息放到三级缓存中(lambda表达式)()->getEarlyBeanReference(...)
这是一个闭环操作,也就是说,他会无限循环下去,要想打破这个闭环,就要从一个地方下手。现在给对象的状态分为两个状态:成品(实例化初始化完成的状态),半成品(实例化没有初始化的对象)在这个闭环当中,其实对象 A和对象B都已经实例化了,都存在半成对象。只不过是没有给属性赋值的半成品其实我们可以把实例化完成的部分进行缓存,我们只要拿到他的地址值就可以了,后续在进行初试完操作。
createBeanInstance(...)(创建B对象,实例化成功,但是还没有初始化)
时间点2:把B的信息放到三级缓存中(lambda表达式)()->getEarlyBeanReference(...)
时间点3:对象A的半成品放入二级缓存,对象A从三级缓存删除
一级缓存没有&&创建中
populateBase
初始化完成初始化未完成
收藏
0 条评论
下一页