文章插图
与一级缓存架构设计的区别在于:
- 新增了二级缓存,用于存放刚实例化的bean;
- 当bean初始化完成后会放入一级缓存,同时将bean从二级缓存中的删除(不需要一式两份,保留一份最终完整的Bean即可)
代理对象的循环依赖在现实开发过程中,我们往往会产生很多的代理对象,当存在代理对象加入到循环依赖流程会是什么样的场景,我们来推演一下,我们仍然使用二级缓存的设计来做推演 。
如果我们在bean初始化完成之后再创建代理对象,整个流程是这样的:
![Spring为什么使用三级缓存而不是两级解决循环依赖问题?](http://img.jiangsulong.com/230228/15251150a-5.jpg)
文章插图
从上图可以非常直观的看出,最终在一级缓存中的对象A是一个proxy_A,但是对象B依赖的对象A却是一个普通A!很明显现有的设计不能够满足代理对象的循环依赖问题 。
如何解决这个问题呢?我们还是在上一个设计上做修改:
- 方案一:在获取到A时立即创建代理,如下图(红色部分)所示:
![Spring为什么使用三级缓存而不是两级解决循环依赖问题?](http://img.jiangsulong.com/230228/1525114I3-6.jpg)
文章插图
这个方案看起来解决了B对象依赖不到A的proxy对象问题,但是又引起了一个致命的问题,在A初始化完成之后还会创建一次代理对象,那么就创建了两次代理对象,他们是完全不一样的,这个代理对象不是单例的了!
- 方案二:在方案一的基础上,我们是不是可以将创建完的proxy_A对象加入到二级缓存中,直接覆盖掉普通A(代理对象会持有普通对象A的引用,所以可以覆盖):这个方案看上去没有问题,但是从设计角度讲,这不符合设计规范,而且覆盖后的A是个代理对象,在后续的操作中,如果再从二级缓存中获取A,这时候就不知道到底获取到的是普通A还是proxy_A了,这无形增加了判断识别的复杂度 。
- 方案三:在首次实例化A的时候就直接创建A的代理对象,并放入二级缓存中:这个方案与方案二有相同的问题,这里不在赘述 。
![Spring为什么使用三级缓存而不是两级解决循环依赖问题?](http://img.jiangsulong.com/230228/15251124D-7.jpg)
文章插图
与二级缓存设计最大的不同点在于:
- 在获取到A时创建proxy_A,同时将其加入到二级缓存中,并返回给B,这样B就依赖了proxy_A;
- 在A初始化过程中会创建代理对象,这时候会做一个检查,也就是会去查询二级缓存,看有没有proxy_A的存在,如果有说明proxy_A已经创建,我们会选择二级缓存中的proxy_A存入一级缓存并返回(因为二级缓存中的proxy_A已经被B依赖);
Spring Bean初始化会产生代理对象的场景在上述流程中,标记位黄色的部分就是两个代理对象的创建的地方,在Spring中就是这两个后置处理器调用的地方,它们分别是:
- 在调用getEarlyBeanReference时如果实现了BeanPostProcessor则会创建代理对象;
- 另一个地方是在执行Bean初始化initializeBean时执行BeanPostProcessor会创建代理对象;
// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isDebugEnabled()) {logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}// addSingletonFactory方法是将bean加入三级缓存中// 三级缓存会被ObjectFactory包装// getEarlyBeanReference方法会执行Bean的后置处理器addSingletonFactory(beanName, new ObjectFactory<Object>() {@Overridepublic Object getObject() throws BeansException {return getEarlyBeanReference(beanName, mbd, bean);}});}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Spring项目不要忽视这个超时配置,否则你的Http调用可能无法结束
- 如何正确的使用一条SQL删除重复数据
- 桥梁竹胶板 桥梁板上为什么有洞
- 鸿运当头为什么叶子蜷缩 鸿运当头叶子枯萎了怎么办
- 为什么十个化疗九个死 有癌症病人的家里阴气太重
- 最新香港电视剧tvb最新电视剧无厘头影视~无厘头大擂台玩了10多分去查询结果说没有q币为什么呢?难道是骗子
- 老天为什么不让圣人出山 圣人2021年几月出山
- 秋葵为什么咬不动
- 抚顺1000字文章 抚顺的作文
- 地狱人形师为什么救乱世狂刀?有关于霹雳布袋戏中的阴阳师和地狱人形师。?