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

彻底理解Spring三级缓存机制

文章目录

  • 前言
  • 一、Spring解决循环依赖时,为什么要使用三级缓存?


前言

  Spring解决循环依赖的手段,是通过三级缓存

  • singletonObjects:存放所有生命周期完整的单例对象。(一级缓存)
  • earlySingletonObjects:存放所有完成了实例化操作的早期单例对象。(二级缓存)
  • singletonFactories:存放单例工厂的对象,通过工厂创建早期Bean。(三级缓存)
    在这里插入图片描述
      具体Spring是如何解决循环依赖问题的,在Spring循环依赖源码分析中已经详细说明,本篇侧重于证明三级缓存的必要性。

一、Spring解决循环依赖时,为什么要使用三级缓存?

  这是一道非常经典的面试题。如果一个对象需要被代理,那首先需要生成一个普通的对象,而代理对象和普通对象是不能同时存在于容器中的,当一个对象需要使用代理的时候,就要使用代理对象覆盖掉原来的普通对象。
  这是一个典型的循环依赖场景,存在两个相互引用的 Bean:A 和 B。其中 A 包含 b 属性,B 包含 a 属性。无论是否存在循环依赖,这两个 Bean 在完成实例化后都会自动存入三级缓存。需要注意的是,通过反射创建的实例对象与放入三级缓存工厂中的对象实际上是同一个引用在这里插入图片描述
  然后A对象执行属性注入,发现需要B属性,B在容器中是不存在的,于是需要去创建B对象。
  B对象在执行属性注入,发现需要A属性,需要从容器中获取:
在这里插入图片描述
  这里从三级缓存中,可以获取到创建A对象的工厂方法,如果A对象需要AOP,则会:
在这里插入图片描述
  为B的A属性赋值时,使用的是经过AOP处理的A对象。在B完成初始化后,A对象完成属性注入并继续初始化流程,此时不会再次进行AOP处理。这意味着A对象和B对象中的A属性实际上指向同一个经过AOP处理的对象实例。这就是三级缓存存在的意义。
  如果仅使用二级缓存,给B的A属性赋值的是未经AOP处理的原始A对象。随后A继续完成后续生命周期并经过AOP处理,导致最终生成的A对象与B持有的A对象不同——前者经过AOP增强,而后者仍是原始对象


  这里可能会有一个疑惑的点,那就是,A对象和B中的A属性应该是同一个实例,如果A继续完成后续生命周期并执行AOP处理,最终将成为AOP增强对象。那么即便最初B获取A属性时,A尚未经过AOP处理,当A完成整个流程后,B中的A是否也会自动成为AOP增强对象?
  答案是否定的,因为Spring 中对 A 做 AOP 是通过“生成一个新的代理对象”,而不是修改原始 A 的引用本身:

  • B 中的 a 是早期注入进去的,它的类型是原始 A
  • Spring 后续创建了 proxyA,它是一个新对象,代理了原始 A
  • 但此时 B 中早就注入好了,不会“回头替换”那个引用
  • 所以 B 中的 A 就是原始对象,没有事务、没有切面

  一个简单案例即可证明:

public class MyService {public void doSomething() {System.out.println("Doing something...");}
}
@Aspect
public class LogAspect {@Before("execution(* MyService.*(..))")public void before() {System.out.println(">>> [AOP] Before method execution");}
}
public class AopTest {public static void main(String[] args) {MyService target = new MyService();// 创建代理工厂并添加切面AspectJProxyFactory factory = new AspectJProxyFactory(target);factory.addAspect(new LogAspect());// 获取代理对象MyService proxy = factory.getProxy();System.out.println("target = " + target.getClass());System.out.println("proxy  = " + proxy.getClass());System.out.println("是否同一引用: " + (target == proxy));proxy.doSomething();}
}

在这里插入图片描述

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

相关文章:

  • MacOs 安装局域网 gitlab 记录
  • Flutter 与 Android 原生布局组件对照表(完整版)
  • 【产品经理从0到1】自媒体端产品设计
  • 017搜索之深度优先DFS——算法备赛
  • 解决 maven编译项目-Fatal error compiling: 无效的目标发行版: 21 -> [Help 1]
  • Thinkphp6实现websocket
  • web-css
  • 关于 smali:2. 从 Java 到 Smali 的映射
  • 三、zookeeper 常用shell命令
  • 分布式流处理与消息传递——Paxos Stream 算法详解
  • 智变与重构:AI 赋能基础教育教学的范式转型研究报告
  • 平衡三进制
  • 针对Python开发的工具推荐及分析,涵盖集成开发环境(IDE)、轻量级工具、在线开发平台、代码管理工具等)
  • 960g轻薄本,把科技塞进巧克力盒子
  • xcode 编译运行错误 Sandbox: rsync(29343) deny(1) file-write-create
  • C# 基于 Windows 系统与 Visual Studio 2017 的 Messenger 消息传递机制详解:发布-订阅模式实现
  • ComfyUI+阿里Wan2.1+内网穿透技术:本地AI视频生成系统搭建实战
  • 腾讯云开发者社区文章内容提取免费API接口教程
  • 利用海外代理IP,做Twitter2026年全球趋势数据分析
  • OpenLayers 图形交互编辑
  • pikachu靶场通关笔记06 XSS关卡02-反射型POST
  • SQLiteStudio - 免费开源、轻量高效,跨平台的 SQLite 数据库管理工具,代替 Navicat for SQLite
  • Prometheus + Grafana + Cadvisor:构建高效企业级服务监控体系
  • WEBSTORM前端 —— 第3章:移动 Web —— 第2节:空间转换、转化
  • Java研学-MongoDB(一)
  • 【AI面试秘籍】| 第25期:RAG的关键痛点及解决方案深度解析
  • OpenGL、GLUT、freeGLUT 与 GLFW 的区别
  • 服务器带宽线路的区别(GIA、CN2、BGP、CMI等)
  • ppt一键制作:ai自动生成PPT,便捷高效超级精美!
  • 多方法解决MNIST数字识别