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 吗?或者你更倾向于“能不循环就不循环”的设计哲学?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1218316.shtml

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

相关文章

为什么go和rust语言都舍弃了继承?

Go 和 Rust 都故意不提供传统的类继承(class inheritance),核心原因高度一致:继承虽然看起来方便,但长期来看它带来的问题往往大于它解决的问题。两门语言的设计者都把“组合优于继承”(Composition over I…

Silk V3音频解码技术实践指南:从环境搭建到故障排除

Silk V3音频解码技术实践指南:从环境搭建到故障排除 【免费下载链接】silk-v3-decoder [Skype Silk Codec SDK]Decode silk v3 audio files (like wechat amr, aud files, qq slk files) and convert to other format (like mp3). Batch conversion support. 项目…

BilibiliDown视频下载工具全攻略:多场景解决方案与高效使用指南

BilibiliDown视频下载工具全攻略:多场景解决方案与高效使用指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_…

Android设备控制与跨平台工具:QtScrcpy零基础入门指南

Android设备控制与跨平台工具:QtScrcpy零基础入门指南 【免费下载链接】QtScrcpy QtScrcpy 可以通过 USB / 网络连接Android设备,并进行显示和控制。无需root权限。 项目地址: https://gitcode.com/GitHub_Trending/qt/QtScrcpy QtScrcpy是一款专…

戴森球计划蓝图仓库新手指南:零门槛构建高效生产体系

戴森球计划蓝图仓库新手指南:零门槛构建高效生产体系 【免费下载链接】FactoryBluePrints 游戏戴森球计划的**工厂**蓝图仓库 项目地址: https://gitcode.com/GitHub_Trending/fa/FactoryBluePrints 戴森球计划FactoryBluePrints蓝图仓库是新手玩家快速掌握高…

YOLOE部署踩坑记录:这些错误千万别犯

YOLOE部署踩坑记录:这些错误千万别犯 刚拿到YOLOE官版镜像时,我满心期待——开放词汇检测、零样本迁移、实时分割,听起来就像给目标检测装上了“人眼大脑”。可现实很快给了我一记重击:第一次运行predict_text_prompt.py就卡在CU…

mptools v8.0在CS32系列中的应用完整示例

以下是对您提供的博文内容进行 深度润色与结构重构后的技术文章 。我以一位资深嵌入式系统工程师兼教学博主的身份,彻底摒弃模板化表达、AI腔调和教科书式分段,转而采用 真实项目现场的语言节奏 工程师间对话感 关键细节深挖 可复用的实战经验沉淀…

如何通过用户脚本优化123云盘使用体验

如何通过用户脚本优化123云盘使用体验 【免费下载链接】123pan_unlock 基于油猴的123云盘解锁脚本,支持解锁123云盘下载功能 项目地址: https://gitcode.com/gh_mirrors/12/123pan_unlock 123云盘作为常用的文件存储与分享平台,其基础功能常受限于…

3步完成LivePortrait跨平台部署:让静态肖像动起来的AI工具全指南

3步完成LivePortrait跨平台部署:让静态肖像动起来的AI工具全指南 【免费下载链接】LivePortrait Bring portraits to life! 项目地址: https://gitcode.com/GitHub_Trending/li/LivePortrait 你是否想过让老照片里的人物微笑、让手绘肖像转头说话&#xff1f…

深度测评9个AI论文网站,专科生轻松搞定毕业论文!

深度测评9个AI论文网站,专科生轻松搞定毕业论文! AI 工具如何助力专科生轻松应对毕业论文 在当前的学术环境中,AI 工具已经成为许多学生解决论文写作难题的重要助手。尤其是对于专科生而言,面对繁重的学业压力和对论文格式、内容…

英雄联盟LCU接口应用框架:Akari技术架构与实践指南

英雄联盟LCU接口应用框架:Akari技术架构与实践指南 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 项目概述 League-…

打造智能协作机械臂: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…

B站直播推流专业指南:从原理到实战的技术解析

B站直播推流专业指南:从原理到实战的技术解析 【免费下载链接】bilibili_live_stream_code 用于在准备直播时获取第三方推流码,以便可以绕开哔哩哔哩直播姬,直接在如OBS等软件中进行直播,软件同时提供定义直播分区和标题功能 项…

Qwen3-1.7B效果惊艳!猫娘角色生成案例展示

Qwen3-1.7B效果惊艳!猫娘角色生成案例展示 你有没有试过,和一个既会撒娇又带点小傲娇、说话软糯还藏着小心思的虚拟角色聊天?不是冷冰冰的问答机器人,而是真正能让你心头一颤、嘴角上扬的“猫娘”——她会因为你一句“我不爱你了…

解密高效翻译:Crow Translate如何引发效率革命

解密高效翻译:Crow Translate如何引发效率革命 【免费下载链接】crow-translate Crow Translate - 一个用C/Qt编写的简单轻量级翻译器,支持使用Google、Yandex、Bing等API进行文本翻译和朗读。 项目地址: https://gitcode.com/gh_mirrors/cr/crow-tran…

YimMenu游戏助手完全掌握指南:从入门到精通

YimMenu游戏助手完全掌握指南:从入门到精通 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenu 核…

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

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

如何解决AList夸克TV驱动授权二维码过期问题:3种实用方案

如何解决AList夸克TV驱动授权二维码过期问题:3种实用方案 【免费下载链接】alist alist-org/alist: 是一个基于 JavaScript 的列表和表格库,支持多种列表和表格样式和选项。该项目提供了一个简单易用的列表和表格库,可以方便地实现各种列表和…

降噪麦克风搭配使用,识别准确率再提升

降噪麦克风搭配使用,识别准确率再提升 在日常语音识别实践中,很多人会遇到一个共同问题:明明模型很强大,但识别结果却总差那么一口气。尤其在会议记录、远程访谈、教学录音等真实场景中,环境噪音、设备差异、说话习惯…

光纤光源聚焦模式的像差效应

摘要 光纤是光学系统中广泛使用的光源。因此,研究光学系统的像差对光纤模式传播的影响是有意义的。在本用例中,我们使用VirtualLab Fusion中的快速物理光学引擎来演示由阶跃或梯度折射率光纤产生的一组模式的形状,以及由它们的组合产生的光…