news 2026/6/12 11:51:38

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/10 14:59:16

浅析51单片机复位电路与LED共板设计问题

以下是对您提供的博文内容进行 深度润色与专业重构后的版本 。整体风格更贴近一位有十年嵌入式开发经验、常年带学生做PCB实战的工程师博主口吻——语言自然流畅、逻辑层层递进、技术细节扎实可信,同时彻底去除AI写作痕迹(如模板化表达、空洞术语堆砌、…

作者头像 李华
网站建设 2026/5/28 21:11:09

告别消息撤回烦恼:WeChatIntercept让每一条信息都有迹可循

告别消息撤回烦恼:WeChatIntercept让每一条信息都有迹可循 【免费下载链接】WeChatIntercept 微信防撤回插件,一键安装,仅MAC可用,支持v3.7.0微信 项目地址: https://gitcode.com/gh_mirrors/we/WeChatIntercept 你是否遇到…

作者头像 李华
网站建设 2026/6/10 18:39:12

vivado2022.2安装教程助力智能制造设备开发

以下是对您提供的博文内容进行 深度润色与结构重构后的技术博客正文 。本次优化严格遵循您的全部要求: ✅ 彻底去除AI痕迹,语言自然、专业、有“人味”——像一位在智能制造一线摸爬滚打多年的FPGA工程师,在茶歇时给同事手绘板书式分享&am…

作者头像 李华
网站建设 2026/6/4 6:27:45

如何解决Windows快捷键失效问题:系统级热键冲突解决方案

如何解决Windows快捷键失效问题:系统级热键冲突解决方案 【免费下载链接】hotkey-detective A small program for investigating stolen hotkeys under Windows 8 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 副标题:3大核心收…

作者头像 李华
网站建设 2026/6/11 19:22:44

Snap Hutao:开源原神效率工具的技术解析与实践指南

Snap Hutao:开源原神效率工具的技术解析与实践指南 【免费下载链接】Snap.Hutao 实用的开源多功能原神工具箱 🧰 / Multifunctional Open-Source Genshin Impact Toolkit 🧰 项目地址: https://gitcode.com/GitHub_Trending/sn/Snap.Hutao …

作者头像 李华