【实践向】当移除了三级缓存……
创始人
2024-05-13 03:13:51
0

本文会手把手带你一起把使用二级缓存替换三级缓存,看下移除了三级缓存,只有二级缓存会出什么问题,用实践回答那个被问了无数次的“为什么要有三级缓存?”以及“二级缓存解决不了循环依赖问题吗?”等类似问题( ̄∇ ̄)

既然要用二级缓存替换三级缓存,我们大致回忆下(b_d)都在哪里用到了三级缓存?

自问自答:主要是两个地方:

  1. 获取Bean的时候,Spring在获取Bean的时候,会先从一级缓存中找,找不到会去二级缓存中找,再找不到会到三级缓存

  1. 创建完Bean的实例对象后,会将当前bean以及它的工厂对象添加进三级缓存

那我们分别将这两个地方中涉及到三级缓存的逻辑修改下

移除三级缓存

移除向三级缓存中查找Bean的逻辑

先来到Spring中使用三级缓存的位置,就是DefaultSingletonBeanRegistry类中,不知道如何找的客官可以参考

【Spring源码】2.试个水先~Debug找到传说中的三级缓存

DefaultSingletonBeanRegistry类中有个getSingleton()的方法,里面是从缓存中获取Bean的逻辑

我们把这个函数整个复制下,把原来的注释掉,在复制的函数中进行修改

注意尽量不要直接在原函数上进行修改,因为后面我们还要再改回来呢(˶‾᷄ ⁻̫ ‾᷅˵)

改成这样

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);return singletonObject;}   }return singletonObject != null ? singletonObject : null;
}

移除向三级缓存中添加Bean的逻辑

了解Bean的创建流程的客官还记不记得有个叫做addSingletonFactory()的方法(可以参考文章【Spring源码】16. Bean的创建过程(2) )

这个方法就在DefaultSingletonBeanRegistry类中

当前bean以及它的工厂对象就是在这个方法中被放入三级缓存的

我们想要移除三级缓存,只保留二级缓存,就需要把这个方法中对于三级缓存的操作修改为只保留二级缓存的操作

单击方法回到它位于doCreateBean()方法中的调用位置

addSingletonFactory()方法中操作了三个集合:singletonFactories(三级缓存)、earlySingletonObjects(二级缓存)、registeredSingletons(注册bean集合)

去除三级缓存,我们只添加对earlySingletonObjects(二级缓存)、registeredSingletons(注册bean集合)这两个集合的操作

由于这两个集合是类DefaultSingletonBeanRegistry私有的(private),因此想要在别的类中调用需要修改成公共的(public)

执行测试

修改完毕,我们执行下上篇文章中的测试代码看是否会报错(想要自己亲自执行下的可以直接去为文章

【保姆级】手把手Debug循环依赖的整体流程 中复制下)

嘿嘿没问题对不对,所以其实单纯的循环依赖,二级缓存就足够了,那么为什么非要再搞一个三级缓存呢?

又自问自答:因为代理

引入代理

新建测试类

代理类

我们再新建一个日志类(AOP必然产生动态代理)

package com.aqin.custom.circulate;/** * @Description* @Authoraqin1012 AQin. * @Date11/23/22 1:19 PM * @Version1.0 */
public class MyLogger {public void beforeMethod() {System.out.println("beforeMethod");}public void afterMethod() {System.out.println("afterMethod");}}

配置类

在原有配置基础上,添加日志类以及AOP相关配置

添加依赖

在module下的build.gradle文件中添加AOP的依赖

不然会报下面👇的异常

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0': Cannot create inner bean '(inner bean)#3a883ce7' of type [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice] while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#3a883ce7': Resolution of declared constructors on bean Class [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice] from ClassLoader [sun.misc.Launcher$AppClassLoader@73d16e93] failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/lang/JoinPoint

启动类

public class Test {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("circulate.xml");BeanA beanA = applicationContext.getBean(BeanA.class);System.out.println(beanA);System.out.println(beanA.getBeanB());}}

启动类添加一行方法的调用,用于测试AOP的执行效果

启动执行

果然、报错了=[,,_,,]:3

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'beanA': Bean with name 'beanA' has been injected into other beans [beanB] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.

点击上图中黄色框框框住的类,会定位到报错位置

所以是在执行doCreateBean()方法时,报了这个异常

我们大致翻一下(分析在最后一部分)

在上下文初始化过程中遇到的异常 - 取消刷新尝试:org.springframework.beans.factory.BeanCurrentlyInCreationException。创建名称为'beanA'的Bean时出错。名字为'beanA'的Bean已经作为循环引用的一部分被注入到其他Bean[beanB]的原始版本中,但最终被包装了。这意味着上述其他Bean没有使用Bean的最终版本。这通常是过于急切的类型匹配的结果--例如,考虑使用'getBeanNamesForType'并关闭'allowEagerInit'标志。

将代码改回去

执行成功(。・ω・。)ノ

分析与总结

上面的实践过程直观的证明了一个我们早就知道的结论(˶‾᷄ ⁻̫ ‾᷅˵):

如果不存在代理对象,二级缓存就可以解决循环依赖性的问题,但是当存在代理对象的时候,二级缓存则无法完全解决循环依赖,需要引入三级缓存

相关内容

热门资讯

会主持词开场白 会主持词开场白  篇一  尊敬的各位领导、各位来宾  各位公司同仁:  大家下午好!  非常高兴和大...
中国人寿保险公司晨会主持词 中国人寿保险公司晨会主持词  主持词由主持人于节目进行过程中串联节目的串联词。以下是小编整理的中国人...
公司中秋晚会主持词 关于公司中秋晚会主持词  主持词分为会议主持词、晚会主持词、活动主持词、婚庆主持词等。在当今不断发展...
小学生职位竞选词 小学生职位竞选词  个人觉得竞选中队长,你已经很清楚中队长需要做的事情了,那么就从每一个任务来发展一...
在结婚典礼上的精彩幽默主持词 在结婚典礼上的精彩幽默主持词各位来宾:大家好!奉新郎新娘之命,我来主持今天的婚礼。为什么新郎新娘一定...
婚礼主持人搞笑台词 婚礼主持人搞笑台词  各位来宾:  大家好!奉新郎新娘之命,我来主持今天的婚礼,婚礼主持人搞笑台词。...
幼儿园运动会主持稿 幼儿园运动会主持稿  篇一:幼儿园运动会主持词  踏着春天的脚步,踩着春风的节拍,春天已经来到我们中...
小学庆元旦活动主持词 小学庆元旦活动主持词  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。在当今社会生活中,...
爵士舞蹈串词主持词   爵士舞即美国现代舞,是一种急促又富动感的节奏型舞蹈,是属于一种外放性的舞蹈,不像古典芭蕾舞或现代...
幼儿园元旦节目主持词   齐x:亲爱的爸爸妈妈  周x:亲爱的爷爷奶奶  王x:亲爱的老师  李x:亲爱的小朋友们  合:...
运动会运动员赞美词 运动会运动员赞美词1.赞运动员是我们的目标,是我们的信念,在清凉的初秋,在喧嚣的田径场上,。你们点燃...
黄梅戏晚会的主持词 黄梅戏晚会的主持词  戏迷欢庆四一八 黄梅又添新奇葩  ——喜迎418暨欢庆黄梅戏艺术团成立的晚会台...
学校秋季运动会开幕主持词 学校秋季运动会开幕主持词(精选6篇)  主持词要注意活动对象,针对活动对象写相应的主持词。在当今社会...
庆祝五四文艺晚会主持稿 庆祝五四文艺晚会主持稿  男:尊敬的各位领导、来宾  女:电视机前的观众朋友们  合:大家好  男:...
最新品鉴会主持词 最新品鉴会主持词  鉴会现在开始!  女:各位领导,各位嘉宾  男:女士们、先生们  合:大家下午好...
端午节晚会主持词 精选端午节晚会主持词(通用8篇)  根据活动对象的不同,需要设置不同的主持词。时代不断在进步,很多场...
论坛一周年庆典晚会主持词 论坛一周年庆典晚会主持词  主持词是由主持人于节目进行过程中串联节目的串联词。如今的各种演出活动和集...
最新研讨会主持词 最新研讨会主持词(通用11篇)  主持词分为会议主持词、晚会主持词、活动主持词、婚庆主持词等。在现在...
重阳节的主持词 重阳节的主持词  主持词分为会议主持词、晚会主持词、活动主持词、婚庆主持词等。在人们越来越多的参与各...