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

Spring二级缓存为什么不行(详细)

概述

        对于spring为什么二级缓存不行,一定要用三级缓存,网上的说法很多,好多都是说了个大概,自己整理查阅了一下,终于弄透彻了。(主要讲解一级缓存加二级缓存为什么不行

开讲

        为什么要有spring三级缓存?

这个问题大家应该都明白,为了解决循环依赖问题呗,对吧,怎么解决循环依赖的呢?

噢大家都知道,例如我现在又一个Class A, 一个Class B,并且Bean A依赖Bean B,Bean B依赖Bean A

那么在注入的时候是什么样子的,首先创建A的时候实例化之后,需要属性注入B,这时候将A的ObjectFactory放到三级缓存当中,然后去创建B,实例化之后,注入A的时候就能够到三级缓存中获取到A的早期对象注入给B,完成B的创建,进而回去完成A(如果A要创建代理对象则返回的是代理对象,不用代理就是未初始化的原始对象)的创建,解决了循环依赖的问题。

那我如果只有二级缓存行不行呢?

删掉三级缓存

这个样子,我去掉三级缓存,我在实例化A之后,判断A是否需要创建代理对象,如果需要代理对象则创建代理对象并加入二级缓存,不需要就把原始的对象加入二级缓存,可以吗?

先说结论:如果A不需要代理,那么二级缓存是可以解决循环依赖问题的,但是如果A需要代理,那么三级缓存时不能删掉的?

如果A不需要代理,那么就很简单生成一个半成品原始对象,放到二级缓存中,B需要时直接注入,最后把A完全初始化后(执行初始化方法和Bean后置处理器的后置方法),将A放入一级缓存,没有什么问题。

那么为什么需要代理的时候就会产生问题呢?

因为三级缓存不仅仅是做了创建返回代理对象或者原始对象这件事情,他其实还做了其他事情。

注:B 实例化后需要注入 A,从三级缓存取 ObjectFactory,执行 getObject() → 调用 getEarlyBeanReference。getEarlyBeanReference 会遍历 BeanPostProcessor,最终执行到 AbstractAutoProxyCreator 的 getEarlyBeanReference 方法

来看代码:

bean传的是原始半成品的A对象,最后决定是返回代理对象还是原始对象的是最下面这行代码,我们的例子经过这个方法最终生成了A的代理对象,假设为(0x333),此时B中的A属性就被赋值成了(0x333),但是在这行代码上面还做了一件事情,将这个bean保存到earlyProxyReferences当中,这个map是用来标识当前bean是否生成过代理对象的,因为A如果需要代理,肯定会被加到这个里面。

那如果我们是取掉三级缓存,自己在二级缓存中存储了A的代理对象,而没有在这个map中保存这个bean已经被代理过了,会发生什么?来看看Bean后置处理器的逻辑

可以看到A初始化之后,执行后置处理器逻辑的时候会判断当前的Bean是否已经被代理过,如果没有并且需要生成代理对象的话,那么就会为A再创建一个代理对象(0x444)

执行

Object finalExposedObject = exposeObject; // exposeObject 此时是 A代理对象(0x444)
if (earlySingletonExposure) {// 从二级缓存获取早期代理 0x333Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {// 因为 exposeObject(0x444)!= bean(0x111,原始对象),所以将最终对象是 0x444if (exposeObject == bean) {finalExposedObject = earlySingletonReference;}}
}
// 将最终对象 0x444 存入一级缓存
addSingleton(beanName, finalExposedObject);

这样B中存的是代理对象0x333,而实际上最终保存的是0x444,就出现了不一致问题,并且三级缓存时延迟加载的,只有循环依赖出现的时候我们才会用到它,不需要每次都去调用三级缓存。

http://www.xdnf.cn/news/1443943.html

相关文章:

  • Docker学习笔记(一):容器基础、生态与安装实践
  • 鸿蒙NEXT开发实战:图片显示、几何图形与自定义绘制详解
  • 编辑器vim(Linux)
  • 【Python接口自动化】调用飞书机器人
  • 树莓派 AT 指令串口助手
  • Mysql学习第五天 Innodb底层原理与Mysql日志机制深入剖析
  • K8s生产级Redis集群:Operator模式实现自动扩缩容 详细内容
  • 稳居全球TOP3:鹏辉能源“3+N” 布局,100Ah/50Ah等户储电芯产品筑牢市场优势
  • 域内的权限提升
  • 计算机网络模型总概述
  • 从检索的角度聊聊数据结构的演进​
  • 基于springboot的在线答题练习系统
  • 【vulhub】thinkphp漏洞系列
  • Java设计模式之结构型—适配器模式
  • 需求调研的核心目标
  • 并发编程——14 线程池参数动态化
  • 前端自动化打包服务器无法安装高版本 Node.js v22 问题解决
  • 京东商品评论API接口概述,json数据返回
  • 51单片机:发光二极管与动态数码管控制
  • 迅为RK3568开发板体验OpenHarmony—烧写镜像-安装驱动
  • dumpsys alarm 简介
  • 关于kafka:consumer_offsets日志不能自动清理,设置自动清理规则
  • Trae x Vizro:低代码构建专业数据可视化仪表板的高效方案
  • 小迪web自用笔记25
  • 年成本下降超80%,银行数据治理与自动化应用实录
  • DS1202示波器的使用教程笔记
  • 【C++八股文】数据结构篇
  • 【Python-Day 42】解锁文本处理神技:Python 正则表达式 (Regex) 从入门到实战
  • FPGA离群值剔除算法
  • wpf 自定义输入ip地址的文本框