【实践向】当移除了三级缓存……

news2024/11/23 12:37:46

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

既然要用二级缓存替换三级缓存,我们大致回忆下(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相关配置

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="beanA" class="com.aqin.custom.circulate.BeanA"><property name="beanB" ref="beanB"></property></bean><bean id="beanB" class="com.aqin.custom.circulate.BeanB"><property name="beanA" ref="beanA"></property></bean><bean id="myLogger" class="com.aqin.custom.circulate.MyLogger"></bean><aop:config><aop:aspect id="myLogger" ref="myLogger"><aop:pointcut id="method" expression="execution(* com.aqin.custom.circulate.*.*(..))"/><aop:before method="beforeMethod" pointcut-ref="method"/><aop:after method="afterMethod" pointcut-ref="method"/></aop:aspect></aop:config></beans>

添加依赖

在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'标志。

将代码改回去

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

分析与总结

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/168717.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“Flash配置不当漏洞”详解

危害 可被用来进行跨域访问&#xff0c;可能会导致“跨站点伪造请求”或“跨站点跟踪”&#xff08;“跨站点脚本编制”的变体&#xff09;之类的攻击&#xff0c;从而导致其它用户的信息被非法读取。 导致不受信任的第三方域的flash也能访问当前域的资源&#xff0c;绕过同源策…

一、构建自己的图像分类数据集(Datawhale组队学习)

文章目录安装配置环境图像采集采集函数爬取一类图片爬取多类图片一些参考类别的关键词制作图像分类数据集的注意事项删除多余文件删除系统自动生成的多余文件删除gif格式的图像文件删除非三通道的图像统计图像尺寸、比例分布采用的数据集统计数据集的基本信息可视化图像尺寸分布…

Embarcadero Dev-C++第一次使用注意事项

Embarcadero Dev-C第一次使用注意事项 Embarcadero Dev-C简介 2000年左右&#xff0c;Bloodshed software开发了Dev-C &#xff0c;提供轻量、免费、开源的C/CIDE。Dev-C是最适合初学C语言的IDE之一&#xff0c;但至2015年Dev C5.11&#xff0c;停止了更新维护了。 后来&…

springboot,vue电影院售票系统

开发工具&#xff1a;IDEA服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8项目构建&#xff1a;maven数据库&#xff1a;mysql5.7系统用户前台和管理后台两部分&#xff0c;项目采用前后端分离前端技术&#xff1a;vue elementUI服务端技术&#xff1a;springbootmybatis项目功…

pom文件中自定义的repository不生效

问题描述 对应的pom中依赖获取失败 pom文件依赖配置如下: <dependencies><dependency><groupId>it.geosolutions</groupId><artifactId>geoserver-manager</artifactId><version>1.7.0</version><exclusions><excl…

verilog学习笔记- 15)动态数码管显示实验

目录 简介&#xff1a; 实验任务&#xff1a; 硬件设计&#xff1a; 程序设计&#xff1a; 下载验证&#xff1a; 简介&#xff1a; 由于一般的静态驱动操作虽然方便&#xff0c;但占用的 I/0 口较多&#xff0c;例如要驱动6 位 8 段数码管&#xff0c;以静态驱动方式让数…

值得收藏的30道Python基础练手题(附详解)

今天给大家分享30道Python练习题&#xff0c;建议大家先独立思考一下解题思路&#xff0c;再查看答案。 1. 已知一个字符串为 “hello_world_JMzz”&#xff0c;如何得到一个队列 [“hello”,”world”,”JMzz”] &#xff1f; 使用 split 函数&#xff0c;分割字符串&…

ESP8266 ArduinoIDE 闪存文件操作系统

一、闪存文件系统基本操作 esp8266 的采用 SPIFFS 嵌入式文件系统&#xff0c;在内部 Flash 为 4M&#xff0c;其中 1M 用于存储程序&#xff0c;其他的空间有一部分用于系统&#xff0c;3M 中剩下的大部分空间可以用来存放文件。 其中这个空间大小是可以自定义的&#xff0c;…

【Node.js实战】一文带你开发博客项目之安全(sql注入、xss攻击、md5加密算法)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

Netty进阶

三. Netty 进阶 1. 粘包与半包 1.1 粘包现象 服务端代码 public class HelloWorldServer {static final Logger log LoggerFactory.getLogger(HelloWorldServer.class);void start() {NioEventLoopGroup boss new NioEventLoopGroup(1);NioEventLoopGroup worker new Ni…

想要全面了解DevOps,从概念、实现相关工具到如何落地,看这篇就够了

我们总是在提DevOps&#xff0c;敏捷管理&#xff0c;但大家未必真的明白什么是DevOps。本文是将向大家介绍到底什么是DevOps&#xff0c;DevOps的初衷到底是为了解决什么问题&#xff1f;它能够如何实现&#xff1f;能够带来哪些价值&#xff1f;来让大家对DevOps有一个全面的…

Vscode++Opencv+Anaconda+Python安装教程

最近在学习opencv的时候vscode一直报这个错&#xff1a; Import “cv2” could not be resolved Pylance (reportMissingImports) 但是在Jupyter上面可以运行&#xff0c;一直没找到解决方法&#xff0c;无奈只好重装。 一&#xff1a;安装AnacondaPython 进入Anaconda官网 w…

计网必会:封装、协议、解封装

文章目录解释什么是封装什么是协议解封装是啥封装过程拓展知识需要了解解释 什么是封装 封装就是给初始的数据增加“数据”&#xff0c;让原始数据的信息量扩大&#xff0c;方便层与层间的交流&#xff0c;所谓封装&#xff0c;就是包装的意思&#xff0c;中文博大精深哈哈哈…

03.指针的进阶2.练习题(重点)

1.指针和数组笔试题解析 //1. sizeof(数组名)&#xff0c;数组名表示整个数组。计算的是整个数组的大小,单位是字节 //2. &数组名&#xff0c;数组名表示整个数组。取出的是整个数组的地址 //除此之外&#xff0c;所有的数组名都是数组首元素的地址 EG1:整型 int main…

爬虫学习笔记

目录一、Python基础知识回顾1、pip下载源2、pycharm设置作者信息3、python注释4、变量4.1 类型转换二、Urllib使用一、Python基础知识回顾 1、pip下载源 pip install python包默认是从 https://files.pythonhosted.org/ 网站&#xff08;国外网站&#xff09;上下载&#xff…

CV【3】:drop_out drop_path

文章目录前言1. drop_out1.1. 出现的原因1.2. 概念1.3. 工作原理1.4. 尺度匹配问题1.5. 有效缓解过拟合的原因1.6. 代码实现2. drop_path2.1. 与 drop_out 的差异2.2. 工作原理2.3. 在网络中的应用2.4. 代码实现前言 本文主要对比了两种正则化方法&#xff1a;drop_out 和 dro…

Javascript 组合模式

组合模式 简介 组合模式将对象组合成树形结构&#xff0c;以表示“部分-整体”的层次结构。除了用来表示树形结构之外&#xff0c;组合模式的另一个好处是通过对象的多态性表现&#xff0c;使得用户对单个对象和组合对象的使用具有一致性 请求在树中传递的过程 在组合模式中&…

Express框架连接MySQL数据库操作

在上一篇中已经在Node.js中引入使用了mysql模块进行数据库的基本操作&#xff0c;在本篇当中在Express框架中来连接数据库以及操作数据库&#xff1b; Express 项目环境 这里是通过全局安装Express框架生产的项目环境&#xff0c;也可以通过局部安装的方式&#xff0c;安装过程…

同济子豪兄带我学pytorch图像分类-task01(数据集准备)

学习准备&#xff1a; 本机配置环境的过程很繁琐&#xff0c;考虑时间的问题&#xff0c;直接租一个云服务器。 学习过程中代码没有出现任何问题&#xff0c;代码具有很高的时效性。竟然没有一个语法报错。 所有图片均来源于网络&#xff0c;若有侵犯&#xff0c;多有抱歉 …

Kubernetes 1.25.4版本安装

Kubernetes 1.25.4版本安装 1 配置 1.1 环境介绍 OS&#xff1a;CentOS Linux release 8.5.2111 机器: IPhostname10.104.10.201k8s-master10.104.10.202k8s-node110.104.10.203k8s-node2 所有机器&#xff0c;都将yum源改为国内阿里云开源镜像源 cd /etc/yum.repos.d/ m…