Spring的循环依赖,简明易懂,只看这一篇就够啦

Spring的循环依赖博客不少,但大部分罗里吧嗦,关键点没有讲明白。尤其是二级三级缓存必要性的问题,总是讲不清因果逻辑,本人试图总结简化下

一:三级缓存到底存的的是什么
在这里插入图片描述
「singletonObjects」:缓存某个 beanName 对应的经过了完整生命周期的bean;
「earlySingletonObjects」:缓存提前拿原始对象进行了 AOP 之后得到的代理对象,原始对象还没有进行属性注入和后续的 BeanPostProcesso r等生命周期;
「singletonFactories」:缓存的是一个 ObjectFactory ,主要用来去生成原始对象进行了 AOP之后得到的「代理对象」,在每个 Bean 的生成过程中,都会提前暴露一个工厂,这个工厂可能用到,也可能用不到,如果没有出现循环依赖依赖本 bean,那么这个工厂无用,本 bean 按照自己的生命周期执行,执行完后直接把本 bean 放入 singletonObjects 中即可,如果出现了循环依赖依赖了本 bean,则另外那个 bean 执行 ObjectFactory 提交得到一个
AOP 之后的代理对象(如果有 AOP 的话,如果无需 AOP ,则直接得到一个原始对象)。

二:循环处理过程:
1:A 调用doCreateBean()创建Bean对象:由于还未创建,从第1级缓存singletonObjects查不到,此时只是一个半成品(提前暴露的对象),存在于第3级缓存singletonFactories。
2:A在属性填充时发现自己需要B对象,但是在三级缓存中均未发现B,于是创建B的半成品,存在于第3级缓存singletonFactories。
3:B在属性填充时发现自己需要A对象,从第1级缓存singletonObjects和第2级缓存earlySingletonObjects中未发现A,但是在第3级缓存singletonFactories中发现A,将A放入第2级缓存earlySingletonObjects,同时从第3级缓存singletonFactories删除。
4:将A注入到对象B中。
5:B完成属性填充,执行初始化方法,将自己放入第1级缓存singletonObjects中(此时B是一个完整的对象),同时从第3级缓存singletonFactories和第2级缓存earlySingletonObjects中删除。
6:A得到“对象B的完整实例”,将B注入到A中。
7:A完成属性填充,执行初始化方法,并放入到第1级缓存singletonObjects中。

三:第二级缓存是干啥的
在处理过程中我们可以发现,半成品对象其实创建于第三级缓存,但又在第二级缓存中保存了一份,这是为什么呢?涉及到以下一个场景问题:
我们知道Spring的AOP实现在bean初始化(而非实例化)之后,如果 A 的原始对象注入给 B 的属性之后,A 的原始对象进行了 AOP 产生了一个代理对象,此时就会出现,对于 A 而言,它的 Bean 对象其实应该是 AOP 之后的代理对象,而 B 的 a 属性对应的并不是 AOP 之后的代理对象,这就产生了冲突。也就是说B 依赖的 A 和最终的 A 不是同一个对象!

为了解决这个问题,所以“又在第二级缓存中保存了一份半成品对象”

具体说就是
在第三级缓存中执行 ObjectFactory将得到一个A 原始对象经过 AOP 之后的代理对象,然后把该代理对象放入 earlySingletonObjects 中。
此时B可以从 earlySingletonObjects 中得到 A 原始对象的代理对象了,并且是A的同一个代理对象。
当 B 创建完了之后,A 继续进行生命周期,而 A 在完成属性注入后,会按照它本身的逻辑去进行AOP,而此时我们知道 A 原始对象已经经历过了 AOP ,所以对于 A 本身而言,不会再去进行 AOP了

对于 A 而言,进行了 AOP 的判断后,以及 BeanPostProcessor 的执行之后,就需要把 A 对应的对象放入 singletonObjects 中了,但是我们知道,应该是要 A 的代理对象放入 singletonObjects 中,所以此时需要从 earlySingletonObjects 中得到代理对象,然后入 singletonObjects 中。

四:回到最绕脑的几个问题
最常见的问题是说“解决循环依赖必须要三级缓存吗?两级不行吗?”
这个问题其实本身描述的不清晰,因为三级缓存到底是单指第三级缓存earlySingletonObjects,还是三层缓存这种设计呢?
然后博客上一群人再说singletonFactories的作用,另一群人在说earlySingletonObjects的作用,只看答案的话就像你说你的,我说我的。大哥,我们为什么不先确定一下问题的条件,再给出答案呢?

可以不要第一级缓存吗?
连第一级缓存都不要的话,是无法实现单例的

可以不要第二级缓存吗?
如果没有AOP的话确实可以,如果加上AOP,第二级缓存是无法解决的,不可能让第三级缓存earlySingletonObjects每次执行singleFactory.getObject()方法都产生一个新的代理对象,这样还是会造成依赖的 A 和最终的 A 不是同一个对象,所以还要借助另外一个缓存来保存产生的代理对象

可以不要第三级缓存吗?
解决循环依赖,必须要第三级来创建半成品bean,提前暴露出来以供引用。

参考文章:
https://blog.csdn.net/weixin_44129618/article/details/122839774
https://blog.csdn.net/qq_53916344/article/details/127071494
https://englishcode.blog.csdn.net/article/details/124421852

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值