彻底理解Spring三级缓存机制

article/2025/7/31 10:27:51

文章目录

  • 前言
  • 一、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.hkcw.cn/article/TiSxAHmILV.shtml

相关文章

Diffusion Planner:扩散模型重塑自动驾驶路径规划(ICLR‘25)

1. 概述 2025年2月14日,清华大学AIR智能产业研究院联合毫末智行、中科院自动化所和香港中文大学团队,在ICLR 2025会议上发布了Diffusion Planner——一种创新性的基于Diffusion Transformer的自动驾驶规划模型架构。该系统联合建模周车运动预测与自车行…

财管5-投资项目的评价指标现金流量构成

一、投资项目评价指标 独立项目评价指标包括净现值(NPV)、现值指数(PI)、内含报酬率(IRR)、回收期(PP)、会计报酬率; 1、净现值 计算NPV 未来现金流量的现值 - 原始投…

【Bluedroid】蓝牙启动之 l2c_init 源码解析

蓝牙 L2CAP(逻辑链路控制和适配协议)层是蓝牙协议栈的核心传输层,负责为上层协议(如 ATT、SMP、GATT)提供逻辑通道、服务路由和流量控制等关键功能。本文围绕 L2CAP 层的五大核心数据结构(全局控制块tL2C_C…

NACOS 配置中心--数据隔离

1.实现效果 名称空间 -- 区分 多套环境 group 分组 -- 区分多种微服务 data id 数据集 -- 区分多种配置 2.新建命名空间 3.创建 group 和 data id 同逻辑 创建 test 和prod 环境配置 5.yml文件配置进行映射 server:port: 8000 spring:config:import: # 映射data id 和gro…

rtpmixsound:实现音频混音攻击!全参数详细教程!Kali Linux教程!

简介 一种将预先录制的音频与指定目标音频流中的音频(即 RTP)实时混合的工具。 一款用于将预先录制的音频与指定目标音频流中的音频(即 RTP)实时混合的工具。该工具创建于 2006 年 8 月至 9 月之间。该工具名为 rtpmixsound。它…

【java面试】redis篇

一、适用场景 问:你在项目中,都用到了redis,你在最近的哪些场景中使用了redis? 答:(结合实际项目情况) (一)缓存 查询流程: 请求路径: 一个get请求&#x…

行业分析---小米汽车2025第一季度财报

1 背景 最近几年是新能源汽车的淘汰赛,前短时间比亚迪再次开始了降价,导致一片上市车企的股价大跌,足见车圈现在的敏感度。因此笔者会一直跟踪新势力车企的财报状况,对之前财报分析感兴趣的读者朋友可以参考以下博客:…

TensorFlow深度学习实战(19)——受限玻尔兹曼机

TensorFlow深度学习实战(19)——受限玻尔兹曼机 0. 前言1. 受限玻尔兹曼机1.1 受限玻尔兹曼机架构1.2 受限玻尔兹曼机的数学原理 2. 使用受限玻尔兹曼机重建图像3. 深度信念网络小结系列链接 0. 前言 受限玻尔兹曼机 (Restricted Boltzmann Machine, RB…

设计模式——桥接设计模式(结构型)

摘要 桥接设计模式是一种结构型设计模式,用于将抽象与实现解耦,使二者可以独立变化。它通过将一个类拆分为“抽象”和“实现”两部分,并通过桥接关系组合,避免了类继承层次结构过于庞大。桥接模式包含抽象类、扩充抽象类、实现类…

java反射

简介 获取Class 误区 解释一下 “类” 和 “Class对象” 的区别,以及为什么每个类都有关联的 Class 对象: 🧩 核心概念:类 vs Class对象 想象你有一本《汽车使用说明书》: 类 这本说明书本身(纸上的文…

C++ 之 多态 【虚函数表、多态的原理、动态绑定与静态绑定】

目录 前言 1.多态的原理 1.1虚函数表 1.2派生类中的虚表 1.3虚函数、虚表存放位置 1.4多态的原理 1.5多态条件的思考 2.动态绑定与静态绑定 3.单继承和虚继承中的虚函数表 3.1单继承中的虚函数表 3.2多继承(非菱形继承)中的虚函数表 4.问答题 前言 需要声明的&#x…

28 C 语言作用域详解:作用域特性(全局、局部、块级)、应用场景、注意事项

1 作用域简介 作用域定义了代码中标识符(如变量、常量、数组、函数等)的可见性与可访问范围,即标识符在程序的哪些位置能够被引用或访问。在 C 语言中,作用域主要分为三类: 全局作用域局部作用域块级作用域 需注意&am…

day03-Vue-Element

1 Ajax 1.1 Ajax介绍 1.1.1 Ajax概述 我们前端页面中的数据,如下图所示的表格中的学生信息,应该来自于后台,那么我们的后台和前端是互不影响的2个程序,那么我们前端应该如何从后台获取数据呢?因为是2个程序&#xf…

智慧交通设计方案

该文档是智慧交通设计方案,交通设计位于综合交通规划后、道路工程设计前,目标是优化交通系统及设施,实现交通安全、高效、可持续发展。内容涵盖区域交通组织优化(含需求管理、速度管理等)、平面交叉口设计(要素、改善措施)、专项交通设计(公共交通、慢行系统等)、智能…

SAP学习笔记 - 开发17 - 前端Fiori开发 Component 配置(组件化)

上一章讲了Fiori前端开发中的国际化。 SAP学习笔记 - 开发16 - 前端Fiori开发 Properties文件(国际化) ,语言切换实例,Fiori 国际化(常用语言列表,关键规则,注意事项)-CSDN博客 本…

leetcode刷题日记——二叉树的层平均值

[ 题目描述 ]: [ 思路 ]: BFS,通过层次遍历求得每层的和,然后取平均数,存入结果数组树中节点个数在1-10000之间,那么结果数组最大为10000个结果,层数最多为 2n-1>10000,可以推…

Google Android 14设备和应用通知 受限制的设置 出于安全考虑......

重要提示: 文中部分步骤仅适用于 Android 13 及更高版本。了解如何查看 Android 版本。 启用受限制的设置后,应用将能够访问敏感信息,而这可能使您的个人数据面临风险。除非您信任该应用的开发者,否则我们不建议您允许访问受限制…

【小米拥抱AI】小米开源视觉大模型—— MiMo-VL

MiMo-VL-7B模型的开发包含两个序贯训练过程:(1)四阶段预训练,涵盖投影器预热、视觉-语言对齐、通用多模态预训练及长上下文监督微调(SFT),最终生成MiMo-VL-7B-SFT模型;(2…

自编码器Auto-encoder(李宏毅)

目录 编码器的概念: 为什么需要编码器? 编码器什么原理? 去噪自编码器: 自编码器的应用: 特征解耦 离散隐表征 编码器的概念: 重构:输入一张图片,通过编码器转化成向量,要求再…