别盲从了,spring 解决循环依赖真的一定需要三级缓存吗?demo结合源码讲解三级缓存的真正目的,一级缓存singletonFactories的真正作用,看到文章最后让面试官眼前一亮

背景

本篇是我上一篇《3分钟秒懂,最简单通俗易懂的spring bean 生命周期介绍与源码分析,附上demo完整源码》姊妹篇

spring 三级缓存问题是面试中的热点问题,大部分回答者会说是为了解决循环依赖问题 有的面试官可能会继续深究,会问那么换成2级缓存不可以吗,singletonFactories
这级缓存具体作用是什么呢,这时候你会如何回答呢?
不卖关子,实际上二级缓存就是可以解决循环依赖问题的,那么为什么还要多一个singletonFactories 的以及緩存呢


我们本篇結合源码查看一下具体为什么需要加一层singletonFactories

demo实现循环依赖

首先我们创建两个互相依赖的类teacher和student,并且创建student的aop代理 ,源码如下:

teacher 源码
在这里插入图片描述

student 源码

在这里插入图片描述

aspect 代理类
在这里插入图片描述

三级缓存解决循环依赖整体流程图

我这画的有点小了,大家方法查看

在这里插入图片描述

三级缓存解决循环依赖流程描述

1.首先初始化student 将自己的factory 放入一级缓存singletonFactories
2.注入teacher 依赖,发现teacher 中有student 依赖
3.断定student为循环依赖,所以执行student的factory 创建对象
3.1 如果对象是aop代理 则getEarlyBeanReference 返回代理对象
3.2 如果对象是正常对象,则直接返回该对象
4. teacher 注入student 的半成本对象,完成注入,初始化完成,teacher 放入成品赤
5. student 完成teacher 注入,初始化完成,student 放入成品吃


结合源码查看代码执行流程

首先是执行doCreateBean 初始化student

在这里插入图片描述

放入对象的factory到一级缓存

在这里插入图片描述
在这里插入图片描述

注入依赖teacher

在这里插入图片描述

注入teacher的依赖student ,发现student 是循环依赖

调用student 的factory获取对象实例

在这里插入图片描述

如果是有aop代理,则直接返回代理对象
在这里插入图片描述
在这里插入图片描述

student 注入完成,teacher初始化完成,放入成品池

在这里插入图片描述

teacher 注入完成,student初始化完成,放入成品池

在这里插入图片描述

初始化完成


思考:spring 为什么要用三级缓存而不是二级缓存(亮点)

我们从源码可以看到,一级缓存singletonFactories 放入的是对象工厂 二级缓存是放入循环依赖时的提前曝光对象
如果去掉一级缓存,直接将二级缓存作为循环依赖时的半成品池,实际上依然可以解决循环依赖问题
可以创建对象就放入二级缓存,不管是循环依赖还是普通注入,最后都可以完成并放入成品池中 那么为什么spring 要使用一级缓存呢
spring 有的类是需要aop代理的,但是我们如果只有二级缓存的情况下
那么流程就得变为每次创建对象的时候都得判断是否有代理,有的话创建代理,然后进行依赖注入 这样就违背了spring
的对象创建原则(既先注入,然后实例化,最后生成代理类) 为了解决这个问题,spring
特意添加了一级缓存,而且一级缓存放入的不是具体的实例,而是一个factory
这样就可以在只有发生循环依赖的情况下才会打破规则(提前创建代理类) 调用 getEarlyBeanReference
这个时候内部wrapIfNecessary再去判断是否是需要生成代理类 如果是需要代理,则创建代理类返回
如果是普通类,则直接返回对应bean 所以归根结底,spring 这样做得目的就是为了最小限度的保留他的bean的创建周期规则
不希望因为小概率的循环依赖aop代理就完全从头开始打破这个规则


通过上面分析我们可以了解,实际上singletonFactories 这个得作用就是在循环依赖出现的情况下,
没有代理时正常返回对象本身,有aop代理情况下直接返回代理,这样就可以最大程度的位置spring
的后置创建代理,不希望因为小概率的循环依赖aop代理就完全从头开始打破这个规则(先依赖注入->创建对象->创建代理对象)

猜你喜欢

转载自blog.csdn.net/madness1010/article/details/129388286