当前位置: 首页 > news >正文

Spring三级缓存核心思想

spring在启动时候,会创建bean,并给bean填充属性,这事会使用到三级缓存

	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一级缓存private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存

我们在理解三级缓存前,先明白什么是实例化,什么叫初始化
实例化就是,创建了对象,不为null了
初始化是,不仅实例化了,属性也得到填充

一、第一级缓存特别简单,保存所有已经实例化并且初始化好的bean;
如果不存在循环依赖,那只需要一级缓存就可以了,可是循环依赖的存在,导致一级缓存不够,举个例子解释下循环依赖,A类有B属性,B类有A属性,在A类初始化过程中发现需要B,就先进行B类的初始化,这时又需要A,那就会进入死循环,不仅仅是A->B->A这种,A->B->C->A也是叫循环依赖,一级缓存是无法解决循环依赖的
二、这时候,我们就需要借用一个集合,存储已经实例化,但是没有初始化的对象,那就是第二级缓存;,我们在实例化A后,将A存放进二级缓存中,再去初始化B,需要使用A填充B属性时,从二级缓存中取,完美解决循环依赖问题
既然循环依赖已经解决,为什么还要有第三级缓存?那又要明白一个新的概念,代理对象,当我们使用AOP时,我们使用的对象,已经不是原生对象,而是代理对象。正常的创建代理对象流程如下:初始化普通对象,创建代理对象,普通对象作为代理对象的属性,当其他对象需要引用该对象时,使用其代理对象。以上环节如果出现循环依赖,怎么做?其实不用三级缓存,也能实现,比如:A为需要使用代理对象,实例化A之后,立即实例化A的代理对象,将A的代理对象放到二级缓存,需要引用A的时候,可以在二级缓存内查询。但是,创建A代理对象的时候,要尽量先初始化A的普通对象(此为规范),所以在实例化A对象后,不创建A代理对象,而是先将A存到三级缓存,初始化A时,如果A使用到B,B需要引用A时,在三级缓存内查询到,此时再创建A的代理对象,因为此时A还没有初始化完成,所以还是先保存至二级缓存,这就是三级缓存的作用。三、三级缓存的作用是,在尽量先初始化对象后再创建代理对象的前提下,将对象先保存至三级缓存,能够解决循环依赖(三级缓存在循环依赖中后续会进二级缓存,没有循环依赖,会进一级缓存)

那为什么会有spring解决不了的循环依赖呢?
1、使用@Scope(“prototype”)[作用是创建新对象,不从缓存中取]的类,A、B循环依赖,且都有该注解;很容易理解,不从缓存中取,那就进入死循环了
2、属性加在构造器里的;此时不是初始化对象用到其他对象,是在实例化时候就需要了,那就没办法了
3、@Async 增强的 Bean 的循环依赖;@Async标记后生成代理对象,和AOP的代理对象不同,所以不会进三级缓存。普通的 AOP 代理都是通过 AbstractAutoProxyCreator 来生成代理类的,AbstractAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor。而 @Async 标记的类是通过 AbstractAdvisingBeanPostProcessor 来生成代理的,AbstractAdvisingBeanPostProcessor 没有实现 SmartInstantiationAwareBeanPostProcessor。
怎解决上面的问题
@Lazy

http://www.lryc.cn/news/30566.html

相关文章:

  • 深度学习算法训练和部署流程介绍--让初学者一篇文章彻底理解算法训练和部署流程
  • 计算机网络整理
  • 闲人闲谈PS之三十八——混合制生产下WBS-BOM价格发布增强
  • Java 根类 Object
  • 04_Apache Pulsar的可视化监控管理、Apache Pulsar的可视化监控部署
  • 【算法】期末复盘,酒店住宿问题——勿向思想僵化前进
  • Java中的Comparator 与 Comparable详解
  • 计算机科学导论笔记(二)
  • GEC6818开发板JPG图像显示,科大讯飞离线语音识别包Linux_aitalk_exp1227_1398d7c6运行demo程序,开发板实现录音
  • 如何判断树莓派通过GPIO与5G模块成功连接?
  • Java——包装类和List及ArrayList
  • matlab - 程序流程控制、函数文件、特殊函数、调试与优化
  • Toponogov 比较定理及其应用
  • 力扣sql简单篇练习(二十二)
  • 【开源硬件】STM32F030R8T6系统板
  • ES之DSL查询文档基础查询
  • 数据结构与算法之堆排序
  • Vue3 中的模板语法
  • Redis十大类型——Hash常见操作
  • Python采集本地二手房,一键知晓上万房源信息
  • Ubuntu 18.04 出现GLIBC_2.28 not found的解决方法(亲测有效)
  • Java文档搜索引擎总结
  • Linux内核学习笔记——页表的那些事。
  • C++,Qt分别读写xml文件
  • WebStorm安装教程【2023年最新版图解】一文教会你安装
  • 用户态和内核态,系统调用
  • Java 包装类
  • Raspberry Pi GPIO入门指南
  • 汇编语言程序设计(三)之汇编程序
  • 用二极管和电容过滤电源波动,实现简单的稳压 - 小水泵升压改装方案