当前位置: 首页 > news >正文

Spring的循环依赖问题

一、循环依赖是怎么产生的?

最经典的场景就是Bean 之间相互引用

@ComponentclassA{@AutowiredprivateBb;}@ComponentclassB{@AutowiredprivateAa;}

🔁 发生了什么?

  1. Spring 创建 A
  2. A 依赖 B → 去创建 B
  3. 创建 B 时发现依赖 A → 又要创建 A
  4. A 还没创建完成 → 卡住 →循环依赖产生

👉 本质:Bean 创建过程中形成闭环依赖


二、Spring 为什么“默认能解决”?

关键点:只支持“单例 + setter/字段注入”的循环依赖

Spring 的解决方案核心是:

⭐ 三级缓存(重点,面试高频)

singletonObjects 一级缓存:完全初始化好的BeanearlySingletonObjects 二级缓存:提前暴露的Bean(半成品) singletonFactories 三级缓存:Bean工厂(用于生成代理对象)

三、解决流程(核心机制)

用 A 和 B 举例:

🧩 步骤拆解:

  1. 创建 A(此时是“半成品”)
  2. 把 A 的ObjectFactory 放入三级缓存
  3. A 依赖 B → 去创建 B
  4. 创建 B 时依赖 A → 尝试获取 A
  5. 从三级缓存拿到 A 的“早期引用”(可能是代理对象)
  6. B 创建完成
  7. 回过头来完成 A 的初始化

👉 这样就绕开了“死循环”


四、为什么需要三级缓存?

很多人会问:二级缓存不够吗?

答案:不够,因为要解决AOP 代理问题

🎯 关键点:

如果 A 需要被代理(比如事务、AOP):

  • 不能直接暴露原始对象
  • 必须暴露代理对象

👉 三级缓存(ObjectFactory)就是为了:

在“提前暴露”时,可以决定返回普通对象还是代理对象


五、哪些情况解决不了?

Spring 不是万能的,这些情况会直接报错:

❌ 1. 构造器注入(Constructor Injection)

classA{publicA(Bb){}}classB{publicB(Aa){}}

👉 原因:
构造器必须“完整对象”,不能用半成品 → 无法提前暴露


❌ 2. 原型(prototype)作用域 多例Bean

@Scope("prototype")

👉 原因:
Spring 不缓存 prototype Bean → 没法用三级缓存


❌ 3. 循环依赖链过于复杂(含 FactoryBean / 动态代理)

比如:

A → B → C → A

或者涉及:

  • FactoryBean
  • BeanPostProcessor
  • 动态代理(AOP 复杂嵌套)
💥 为什么不行?

👉 提前暴露的对象可能:

  • 不是最终形态(还没代理)
  • 或者代理链没构建完成

→ 最终导致:

Bean 创建异常 / 代理错乱


❌ 4. AOP + 循环依赖的“隐形坑”

例如:

@ServiceclassAService{@AutowiredprivateBServicebService;@TransactionalpublicvoidmethodA(){}}

⚠️ 问题点:

  • 提前暴露的是“早期对象”
  • AOP 代理可能还没织入

👉 结果可能是:

事务、切面不生效

(这种不是启动报错,而是运行时“悄悄出 bug”😈)


❌ 5. Spring Boot 2.6+ 默认限制

Spring Boot 2.6开始:

spring.main.allow-circular-references=false

👉 默认禁止循环依赖

💥 表现:

直接启动失败(哪怕是 setter 注入)


六、如何解决循环依赖问题?

✅ 方法1:改成 setter 注入(推荐)

@AutowiredpublicvoidsetB(Bb){this.b=b;}

👉 让 Spring 有机会“先创建半成品”


✅ 方法2:使用 @Lazy(常用技巧)

@Autowired@LazyprivateBb;

👉 延迟加载,相当于:

“等真正用到你再创建”


✅ 方法3:拆分设计(最佳实践)

比如:

ACBC

👉 引入中间层,打断循环


✅ 方法4:使用接口解耦

AIBBIA

👉 降低耦合,避免强依赖闭环


✅ 方法5:手动获取 Bean

ApplicationContext.getBean()

👉 不推荐,但某些场景可用

http://www.jsqmd.com/news/890778/

相关文章:

  • 可微分盲相位搜索:端到端星座整形优化提升光通信频谱效率
  • B站字幕下载终极指南:3步解锁CC字幕提取完整方案
  • 智能打牌记账本:告别手动记账的微信小程序解决方案
  • 终极窗口布局恢复方案:PersistentWindows让多屏工作永不混乱
  • Metasploit渗透测试全流程实战:从边界突破到域控沦陷
  • 2026年贵州高端生肖酱酒品鉴指南:从茅香风格到性价比标杆的完整对标 - 企业名录优选推荐
  • 如何在iOS应用中3步实现专业级视频播放功能:Player库终极指南
  • 基于扩散反演的人脸交换技术:InFS框架原理与工程实践
  • Claude Code用户如何迁移至Taotoken以解决封号与token不足困扰
  • Lovable体育平台用户行为建模实战(含Python+TensorFlow完整代码):从埋点清洗到投注倾向预测
  • 别再盲目喂文档了!Claude长文本推理的5个致命预设误区(92%用户正在踩坑),第3个导致法律意见书生成结果完全不可用
  • 基于混沌映射与LSB改进的高容量安全音频隐写技术解析
  • 如何用feishu2md轻松解决飞书文档迁移难题:三步实现高效格式转换
  • VR教育中测试题设计:提升学习效果与沉浸感的实证研究
  • LlamaParse深度解析:构建高精度多模态文档解析引擎的架构设计与性能优化
  • Trelby剧本创作指南:从零开始掌握专业级开源写作工具
  • FreeRTOS实战解析:互斥量如何化解多任务资源争夺困局
  • Cursor Pro免费激活终极指南:三步解锁完整AI编程功能
  • 保姆级教程:用CubeMX配置STM32F407的TIM3和TIM13,精准控制42步进电机转速与方向
  • 3ds Max渲染许可闲置监控,四款工具谁最省资源
  • Python开发环境配置:从解释器到虚拟环境的工程化实践
  • 2026 上海签证代办公司推荐榜:德国 GmbH 注册、海外子公司搭建、驻外办事处备案、德法西工签申办、企业商事变更靠谱服务机构综合口碑排行详解 - 海棠依旧大
  • 5分钟搞定!RevokeMsgPatcher防撤回工具终极指南:彻底保护你的聊天安全
  • Kohya_SS:现代AI绘画模型训练的技术架构与实践路径
  • 管家婆软件|仅销售预包装食品进货台账录入教程
  • 同城黄金回收服务|余生黄金回收(全国连锁)|大同平城区上门收金 - 润富黄金珠宝行
  • 网页设计公司网站怎么选?2026年最新避坑指南+5个高分案例
  • 基于信息熵最大化的RTOS调度:XIRAC架构实现无限任务与亚微秒级抖动
  • 【ChatGPT批量处理高阶实战指南】:20年自动化工程师亲授17种生产级Prompt编排与API流控技巧
  • ACS Catalysis复旦大学蒋昆&韩国高丽大学Seoin Back:生成式AI加速电催化剂发现:CatGPT助力高效筛选2e⁻-ORR制H₂O₂催化剂