彻底理解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.pswp.cn/web/82163.shtml

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

相关文章

【 SpringCloud | 微服务 网关 】

单体架构时我们只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,这就存在一些问题: 每个微服务都需要编写登录校验、用户信息获取的功能吗? 当微服务之间调…

【前端面经】字节跳动一面

写在前面:面经只是记录博主遇到的题目。每题的答案在编写文档的时候已经有问过deepseek,它只是一种比较普世的答案,要学得深入还是靠自己 Q:三栏布局的实现方式(圣杯模型)如何实现 A: /* 整个 …

ST-GCN

1.bash 安装git 在目录下右键使用git bash打开 需要安装wgetbash download_model.sh,下载.sh文件 wget: command not found,Windows系统使用git命令 下载预训练权重_sh文件下载-CSDN博客 bash tools/get_models.sh 生成了三个.pt文件

计算机网络全维度解析:架构协议、关键设备、安全机制与新兴技术深度融合

计算机网络作为当今数字化社会的基石,其复杂性和应用广泛性远超想象。本文将从基础架构、协议体系、关键设备、安全机制到新兴技术,进行全方位、深层次的解析,并辅以实际应用场景和案例分析。 一、网络架构与分类的深度剖析 1.1 网络分类的立…

大语言模型的推理能力

2025年,各种会推理的AI模型如雨后春笋般涌现,比如ChatGPT o1/o3/o4、DeepSeek r1、Gemini 2 Flash Thinking、Claude 3.7 Sonnet (Extended Thinking)。 对于工程上一些问题比如复杂的自然语言转sql,我们可能忍受模型的得到正确答案需要更多…

黑马程序员C++核心编程笔记--3 函数高级

3.1 函数默认参数 本节内容之前已经整理过,详见22.函数的默认值 3.2 函数占位参数 C中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须补填该位置 语法: 返回值类型 函数名 (数据类型) {} 在现阶段函数的占位参数…

数据仓库分层 4 层模型是什么?

企业每天都在产生和收集海量数据。然而,面对这些数据,许多企业却陷入了困境:如何高效管理、处理和分析这些数据?如何从数据中提取有价值的信息来支持业务决策?这些问题困扰着众多数据分析师和 IT 管理者。 在众多架构…

Java正则表达式完全指南

Java正则表达式完全指南 一、正则表达式基础概念1.1 什么是正则表达式1.2 Java中的正则表达式支持 二、正则表达式基本语法2.1 普通字符2.2 元字符2.3 预定义字符类 三、Java中正则表达式的基本用法3.1 编译正则表达式3.2 创建Matcher对象并执行匹配3.3 常用的Matcher方法 四、…

缓存击穿、缓存雪崩、缓存穿透以及数据库缓存双写不一致问题

在项目中,我们所需要的数据通常存储在数据库中,但是数据库的数据保存在硬盘上,硬盘的读写操作很慢,为了避免直接访问数据库,我们可以使用 Redis 作为缓存层,缓存通常存储在内存中,内存的读写速度…

可灵2.1 vs Veo 3:AI视频生成谁更胜一筹?

在Google发布Veo 3几天后,可灵显然感受到了压力,发布了即将推出的视频模型系列可灵 2.1的早期体验版。 据我了解,有三种不同的模式: 可灵 2.1 标准模式: 720p分辨率 仅支持图像转视频(生成更快,一致性更好) 5秒视频仍需20积分 可灵 2.1 专业模式: 1080p分辨率 仅在图…

解决Docker存储空间不足问题

虚拟机磁盘扩展实战:解决Docker存储空间不足问题 问题背景 在虚拟机中运行的Linux系统上,Docker服务因根分区空间不足而无法正常运行。初始状态如下: [rootlocalhost ~]# df -h / 文件系统 容量 已用 可用 已用% 挂载点…

Redis 中如何保证缓存与数据库的数据一致性?

在 Redis 中保证缓存与数据库的数据一致性,需结合业务场景选择以下策略: 核心策略总结 Cache Aside(旁路缓存)模式 读操作:先查缓存,未命中则查数据库并写入缓存。写操作:先更新数据库&#xf…

晶振频率稳定性:5G 基站与航天设备的核心竞争力

在当今科技飞速发展的时代,电子设备的性能和可靠性至关重要。晶振作为电子设备中的核心部件,为系统提供精确的时间和频率基准。晶振的频率稳定性直接影响着设备的整体性能,从日常生活中广泛使用的智能手机、智能穿戴设备,到对精度…

PDFGear——完全免费且功能强大的PDF处理软件

关键词 :PDFGear、免费、跨平台、多功能、OCR 概要 :PDFGear是一款完全免费且功能强大的PDF处理软件,支持Windows、macOS、iOS和Android等多平台使用。它集PDF阅读、编辑、格式转换、OCR识别及AI智能助手于一体,满足用户多样化文档…

【笔记】在 MSYS2(MINGW64)中正确安装 Rust

#工作记录 1. 环境信息 Windows系统: MSYS2 MINGW64当前时间: 2025年6月1日Rust 版本: rustc 1.87.0 (17067e9ac 2025-05-09) (Rev2, Built by MSYS2 project) 2. 安装步骤 步骤 1: 更新系统包数据库并升级已安装的包 首先,确保我们的 MSYS2 系统是最新状态。打…

WIN11+VSCODE搭建的c/c++环境调试报错解决

解决调试报错 前面win11vscode搭建的c/c环境,ctrlshiftB生成正常,cttlF5运行正常。今天打断点逐步调试时报错,提示找不到库文件。解决方案如下: 下载mingw-w64源码库:(两种途径) 通过MSYS2 UC…

React项目在ios和安卓端要做一个渐变色背景,用css不支持,可使用react-native-linear-gradient

以上有个模块是灰色逐渐到白的背景色过渡 如果是css,以下代码就直接搞定 background: linear-gradient(180deg, #F6F6F6 0%, #FFF 100%);但是在RN中不支持这种写法,那应该写呢? 1.引入react-native-linear-gradient插件,我使用的是…

android-studio-2024.3.2.14如何用WIFI连接到手机(给数据线说 拜拜!)

原文:Android不用数据线就能调试真机的方法—给数据线说 拜拜!(adb远程调试) android-studio-2024.3.2.14是最新的版本,如何连接到手机,可用WIFI,可不用数据线,拜拜 第一步&#xf…

【前端】JS引擎 v.s. 正则表达式引擎

JS引擎 v.s. 正则表达式引擎 它们的转义符都是\ 经过JS引擎会进行一次转义 经过正则表达式会进行一次转义在一次转义中\\\\\的转义过程: 第一个 \ (转义符) 会“吃掉”第二个 \,结果是得到一个字面量的 \。 第三个 \ (转义符) 会“吃掉”第四个 \&#x…

ReactHook有哪些

React 中常用的 Hooks 列表及用法 React Hooks 是 React 16.8 版本引入的一项重要特性,它极大地简化和优化了函数组件的开发过程。以下是 React 中常用的 Hooks 列表及其详细用法: 1. useState useState 是用于在函数组件中添加状态的 Hook。通过调用…