spring循环依赖问题及其处理方案

源于蚂蚁课堂的学习,点击这里查看

1.问题描述

存在多个类,如A、B。。。他们的属性存在环式的依赖关系,A中B类的属性,B中有A类属性。这样当初始化对象的时候,
程序先去创建A,假设AB都是单例情况,发现A中有个B属性,再去创建B,而B中又有A的属性,而A尚未创建完成,那么就会出现相互等待
的死循环。
假设AB都是多例情况,发现A中有个B属性,再去创建B,而B中又有A的属性,而A是多例,又会重新创建A,那么就会出现无限创建新对象
的情况。
spring中默认通过三级缓存帮我们处理好了单例情况下循环依赖的问题(多例必须手动去解决,spring无法判断多例情况下要设置的
对象是哪一个)

 2.源码剖析spring三级缓存解决单例循环依赖

 

 

 

 

 

doCreateBean中主要分三个阶段
1.createBeanInstance通过反射实例化对象
2.populateBean 为对象进行属性赋值
3.initializeBean进行生命周期的后续操作

spring解决循环依赖是通过三级缓存的方式实现的

 

 

 

 

当A对象创建后进行属性赋值,发现依赖于B对象,就会去创建B对象,B对象创建后属性赋值,发现依赖于A对象,去获取A对象时,
此时Object sharedInstance = getSingleton(beanName);就会从缓存中获取值

 

 

3.流程总结

以AB相互依赖为例:
1.首先,我们要明确三级缓存分别的功能
    一级缓存singletonObjects是存放最终完整对象的缓存,所以在获取对象是最先判断此处是否存在对象
    二级缓存earlySingletonObjects是一个中间的、过渡的缓存、存放未进行属性赋值时的对象
    三级缓存singletonFactories是在对象创建好之后尚未进行属性复制前存放的缓存
2.当A对象创建前通过getSingleton方法去缓存取数据,首次,显然为空,那么,就会执行createBeanInstance方法通过反射
调用构造去实例化A对象。
  A对象创建后,会调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))
去将A对象放入三级缓存singletonFactories。
然后通过populateBean方法进行属性赋值,发现属性中有B需要赋值,这时候通过getBean创建B,在此之前,通过getSingleton方法
去缓存取B对象,为空。执行createBeanInstance方法通过反射调用构造去实例化B对象, B对象创建后,会调用
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))
去将B对象放入三级缓存singletonFactories。
然后通过populateBean方法进行属性赋值,发现属性中有A需要赋值,这时候通过getBean->doGetBean->getSingleton中判断
首先判断一级缓存singletonObjects,不存在则,判断二级缓存earlySingletonObjects,不存在则从三级缓存singletonFactories
获取,将A获取出来后将A从三级缓存提升至二级缓存。
这样B对象就可以完成属性赋值(只是不完美,因为A对象未完成属性赋值),B对象之后进行生命周期的init和后置处理后,完成创建,
将B放入一级缓存中
这样A对象的属性赋值得以继续,完成A的属性赋值后,进行生命周期的init和后置处理,A对象也变得完美,将B放入一级缓存中
而由于B对象中A存放的是引用,所以当A对象完美后,B中A指向的对象是一个,故B也完美

4.注意 

 

1.在多例情况下,spring是不会也无法帮我们完成循环依赖问题。因为spring不清楚在注入对象时,到底使用哪个对象设置属性
2.我们可以通过手动set的方式去处理多例情况的循环依赖
3.spring其实通过二级缓存也可以实现循环依赖,但为了方便做spring内部业务扩展,所以才去三级缓存的方式。
可以看出,其实三级缓存对于一级和二级缓存来说,起到一个上下文的功能

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值