news 2026/7/2 1:21:48

spring为什么使用三级缓存而不是两级?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
spring为什么使用三级缓存而不是两级?

Spring 使用三级缓存(而不是两级)来解决循环依赖,主要目的是兼容 AOP(动态代理)场景,同时保持 Bean 创建过程的语义一致性扩展性

如果只用两级缓存,在大多数普通属性注入的循环依赖场景下确实可以工作,但一旦引入 AOP(@Transactional、@Async、@Cacheable 等),就会出现非常严重的问题提前暴露的对象和最终容器里的对象不是同一个(类型/引用不一致),导致运行时类型转换异常、代理失效、事务不生效等。

三级缓存各自职责(DefaultSingletonBeanRegistry)

缓存层级Map 类型存放的内容什么时候放入什么时候取出并移除核心目的
一级缓存 singletonObjects普通 bean(成品)完全初始化好的 bean(可能已代理)初始化完成、放入成品后几乎所有 getBean 最终都走这里成品缓存,正常使用的地方
二级缓存 earlySingletonObjects早期普通对象(半成品)已实例化但还没完成属性填充和初始化的原始对象从三级缓存拿到并暴露早期引用后被其他 bean 依赖时取出,移到一级防止重复创建同一个早期对象
三级缓存 singletonFactoriesObjectFactory(lambda 工厂)生成早期引用的工厂(通常是 getEarlyBeanReference 的 lambda)put 时创建 bean 实例后立即放入第一次被循环依赖时调用 getObject() → 生成早期对象(或代理对象)→ 放入二级延迟决定是否要 AOP 代理的关键点

为什么二级缓存不够?(最核心原因)

假设我们只有一级 + 二级(成品 + 早期普通对象):

A → B → A (A 被 AOP 代理)
  1. 创建 A → 实例化(new A) → 放入二级缓存(早期 A,原始对象)
  2. A 需要注入 B → 创建 B
  3. B 需要注入 A → 从二级缓存拿到原始 A(还没代理)
  4. B 完成 → 放入一级缓存
  5. A 继续 → 填充属性、初始化、AOP 后生成代理对象 proxyA
  6. proxyA 放入一级缓存

问题来了

  • B 手里拿到的 A 是原始 A
  • 容器最终暴露的是proxyA
  • B 拿到的引用和最终容器里的 bean 不是同一个对象!

这会导致:

  • B 调用 A 的方法时绕过了代理 → 事务/日志/权限等切面全部失效
  • 类型检查失败(有些地方强转成代理接口会报错)
  • equals()/hashCode() 异常行为

三级缓存如何解决这个问题?

关键就在第三级:它放的不是对象本身,而是一个 ObjectFactory(lambda),这个 lambda 会在真正被别人依赖的时候才执行:

// 大致伪代码protectedObjectgetEarlyBeanReference(StringbeanName,RootBeanDefinitionmbd,Objectbean){returngetSingleton(beanName,()->{// 这里才是真正决定要不要代理的地方returnapplyBeanPostProcessorsBeforeInitialization(bean,beanName);// → post-processor 可能返回代理对象});}

流程变成:

  1. 创建 A → 实例化 → 放入三级缓存(一个 lambda:getEarlyBeanReference)
  2. A 需要 B → 创建 B
  3. B 需要 A → 从三级缓存拿到 lambda →执行 lambda→ 得到早期引用(如果是 AOP 场景,这里就会提前生成代理对象
  4. 把这个早期引用(可能是代理)放入二级缓存,同时从三级移除
  5. B 拿到的是已经代理好的 A(proxyA)
  6. A 继续后续流程,最终 proxyA 放入一级缓存

结果:B 拿到的 A 和最终容器里的 A 是同一个对象(都是 proxyA),语义一致。

总结一句话

Spring 用三级缓存而不是两级,核心是为了在提前暴露引用时仍然能正确应用 AOP 动态代理,保证“别人提前拿到的引用”和“最终容器里的 bean”是同一个对象。

如果你的项目完全关闭 AOP(never proxy),理论上两级缓存就够了(很多手写 IoC 框架就是这么干的)。但 Spring 要做成通用框架,必须兼容 AOP,所以必须用三级。

你项目里遇到过因为循环依赖 + AOP 导致的诡异 bug 吗?或者你更倾向于“能不循环就不循环”的设计哲学?

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/30 0:12:40

2026年1月重大漏洞威胁情报与分析

2026年1月更新 我们是威胁情报部门,由全球威胁研究人员和数据科学家团队组成,结合数据分析和机器学习(ML)领域的专有技术,分析着世界上规模最大、最多样化的威胁数据集合之一。研究团队提供战术威胁情报,为…

作者头像 李华
网站建设 2026/6/13 20:16:40

3大维度解析GHelper:华硕笔记本性能管理的轻量级革命

3大维度解析GHelper:华硕笔记本性能管理的轻量级革命 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops. Control tool for ROG Zephyrus G14, G15, G16, M16, Flow X13, Flow X16, TUF, Strix, Scar and other models 项目地址…

作者头像 李华
网站建设 2026/7/1 21:36:45

无人机落水钓鱼检测数据集 无人机钓鱼及溺水检测数据集 无人机河道两边钓鱼检测数据集 水边安全监测领域,通过该数据集训练的 AI 模型,可自动识别水边区域的钓鱼行为、溺水风险及船只目标,帮助相关管理部门

无人机落水钓鱼数据集 README 数据集核心信息表 信息类别详细说明类别数量及名称4 类,分别为钓鱼伞(DiaoYuSan)、水边钓鱼(ShuiBianDiaoYu)、游泳溺水(YouYongNiShui)、船只(boat&am…

作者头像 李华
网站建设 2026/6/26 21:53:17

5分钟上手GPEN图像修复,科哥版WebUI一键增强老照片

5分钟上手GPEN图像修复,科哥版WebUI一键增强老照片 你是不是也翻出过泛黄的老相册?那张被岁月模糊了轮廓的全家福、那张边角卷曲却笑容灿烂的毕业照、还有那张因保存不当而布满噪点的童年合影……它们承载着真实的情感,却困在低画质里。现在…

作者头像 李华
网站建设 2026/6/26 23:09:34

打造智能协作机械臂:LeRobot SO-101从硬件到控制全攻略

打造智能协作机械臂:LeRobot SO-101从硬件到控制全攻略 【免费下载链接】lerobot 🤗 LeRobot: State-of-the-art Machine Learning for Real-World Robotics in Pytorch 项目地址: https://gitcode.com/GitHub_Trending/le/lerobot LeRobot SO-10…

作者头像 李华
网站建设 2026/6/29 19:49:30

模拟电子技术基础核心要点:运算放大器初步认识

以下是对您提供的博文《模拟电子技术基础核心要点:运算放大器初步认识》的 深度润色与重构版本 。本次优化严格遵循您的全部要求: ✅ 彻底去除AI腔调与模板化表达(如“本文将从……几个方面阐述”) ✅ 摒弃刻板章节标题&#…

作者头像 李华