什么是循环依赖?Spring 如何解决单例 Bean 的循环依赖?
一、什么是循环依赖循环依赖两个或多个单例 Bean 互相持有对方作为依赖创建时形成死锁无法完成实例化。两种典型场景1. 双向依赖最常见A 里面依赖 BB 里面依赖 Ajava运行Component public class A { Autowired private B b; } Component public class B { Autowired private A a; }2. 多向循环A→BB→CC→A补充三种注入方式对循环依赖的支持setter / 字段注入Autowired 成员变量Spring 可以解决单例循环依赖构造器注入无法解决直接抛BeanCurrentlyInCreationExceptionprototype 多例 Bean完全不支持循环依赖每次新建对象缓存无效二、Spring 解决单例循环依赖核心原理三级缓存Spring 通过DefaultSingletonBeanRegistry维护三个 Map 缓存提前暴露半成品对象解决循环。三级缓存定义java运行// 一级缓存存放完全初始化好的成品单例 Bean private final MapString, Object singletonObjects new ConcurrentHashMap(); // 二级缓存存放实例化完成但还未填充属性、未初始化的半成品 Bean private final MapString, Object earlySingletonObjects new HashMap(); // 三级缓存存放 Bean 的工厂 ObjectFactory用于生成半成品 Bean支持AOP代理 private final MapString, ObjectFactory? singletonFactories new HashMap();各级缓存作用一级缓存 singletonObjects完整创建、属性填充、初始化完毕的 Bean对外正常使用。三级缓存 singletonFactories关键Bean 刚实例化new 对象后立刻把生成当前 Bean 的工厂存入三级缓存。 作用如果该 Bean 需要 AOP 动态代理ObjectFactory 会返回代理对象无 AOP 则返回原生半成品。二级缓存 earlySingletonObjects当出现循环依赖其他 Bean 需要引用半成品时 从三级缓存取出 ObjectFactory生成半成品 / 代理对象放入二级缓存并删除三级缓存对应记录。 避免每次都执行代理逻辑提升性能。缓存查找顺序获取单例 Bean 时顺序一级缓存 → 二级缓存 → 三级缓存一级有直接返回成品一级无、二级有返回半成品一二都无、三级有工厂创建半成品存入二级返回三、分步演示 A、B 循环依赖完整流程字段注入前提A、B 都是单例使用 Autowired 字段注入创建 A先判断一级缓存无 A标记 A 为「正在创建」反射 new A 对象实例化完成属性为空半成品将 A 的 ObjectFactory 放入三级缓存 singletonFactories开始填充 A 的属性发现依赖 B去获取 B创建 B一级缓存无 B标记 B 正在创建new B 半成品将 B 的工厂存入三级缓存填充 B 的属性发现依赖 A去获取 AB 获取依赖 A核心解决点一级缓存无 A二级缓存无 A三级缓存存在 A 的 ObjectFactory取出工厂生成 A 半成品将 A 半成品放入二级缓存 earlySingletonObjects删除三级缓存的 A将半成品 A 注入给 B 的属性B 填充完成执行初始化afterPropertiesSet、init-method完全初始化后的成品 B 放入一级缓存 singletonObjects删除二、三级缓存中 B 的记录回到 A 的属性填充现在可以拿到完整的成品 B注入 A 的属性A 完成初始化成品 A 放入一级缓存删除二三级缓存 A整个流程走完A、B 全部创建完成循环依赖解除。四、关键补充高频面试考点1. 为什么构造器注入无法解决循环依赖三级缓存存入工厂的时机是实例化new 对象之后。 构造器注入需要在 new 对象阶段就传入依赖此时对象还没创建无法提前存入三级缓存暴露半成品直接抛出异常。2. 为什么需要三级缓存只用二级行不行不行三级缓存是为了AOP 动态代理如果 Bean 需要代理ObjectFactory 内部会执行getEarlyBeanReference()创建代理对象若只有二级缓存提前暴露的只能是原生对象后续无法替换成代理对象会导致注入原生对象事务、切面失效。3. prototype 多例 Bean 为什么不能解决循环依赖多例 Bean 不会存入任何一级缓存每次获取都新建对象没有半成品缓存复用机制循环依赖直接无限创建对象报错。4. 开发如何避免循环依赖业务分层解耦调整依赖关系不要互相依赖使用构造器注入循环依赖会直接报错提前发现问题使用Lazy懒加载依赖注入代理对象延迟创建目标 Bean。五、总结循环依赖多个单例 Bean 互相依赖创建闭环Spring 仅支持单例 setter / 字段注入的循环依赖构造器、多例不支持核心方案三级缓存提前暴露半成品 Bean一级完整成品 Bean二级循环依赖临时半成品三级Bean 工厂支持 AOP 代理生成流程核心实例化后先放入三级缓存填充属性时若出现循环取出半成品注入对方完成创建。

相关新闻

ESP32 PICO D4单体翻页时钟:从PCB设计到步进电机驱动的全流程实战

ESP32 PICO D4单体翻页时钟:从PCB设计到步进电机驱动的全流程实战

1. 项目概述:从“翻页”到“单体”的设计哲学翻页时钟,这个带着浓厚复古机械美学的物件,近几年在创客圈和极客爱好者中又火了起来。它不像电子屏那样冰冷地切换数字,而是通过物理页片的“咔哒”翻转,将时间的流逝以一种…

2026/10/24 4:20:54 阅读更多 →
TPIC7710EVM评估板硬件设计与GUI软件实战指南

TPIC7710EVM评估板硬件设计与GUI软件实战指南

1. 项目概述与核心价值在汽车电子和嵌入式系统开发的前期,工程师们最头疼的往往不是写代码,而是如何快速、直观地验证一颗复杂芯片的功能和性能。尤其是像TPIC7710这种集成了电机驱动、电源管理、看门狗、SPI通信等多种功能的汽车电子驻车制动专用ASIC&a…

2026/10/23 13:17:51 阅读更多 →
Jellium Desktop字幕编码问题解决:乱码修复与编码转换

Jellium Desktop字幕编码问题解决:乱码修复与编码转换

Jellium Desktop字幕编码问题解决:乱码修复与编码转换 【免费下载链接】jellium-desktop An unofficial desktop client for Jellyfin 项目地址: https://gitcode.com/GitHub_Trending/je/jellium-desktop Jellium Desktop是一款非官方的Jellyfin桌面客户端&…

2026/10/24 9:51:41 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/24 11:09:31 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/24 17:47:00 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/24 18:34:36 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/24 9:46:55 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/25 3:12:30 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/24 21:09:59 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/24 9:15:56 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/24 11:09:35 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/25 7:47:32 阅读更多 →