怎么解决Spring循环依赖问题

"解决"≠"让 Spring 兜底",而是从根本上消除循环依赖 。

下面给出 4 个层次、12 种落地做法,按"先设计、后代码、再配置、最后兜底"的顺序排列,面试或实战都能直接拿来用。


1. 设计层(根治,推荐)

做法 场景 示例
1. 职责拆分 / 领域建模 两个 Service 互相调 → 抽出第三个 Service OrderService ↔ PaymentService → 抽出 PaymentProcessor
2. 事件驱动 / 消息 解耦同步调用 Spring ApplicationEvent 或 MQ
3. 接口下沉 把共同依赖抽象到 api 模块 A 依赖 B 的接口,B 依赖 A 的接口

2. 代码层(低成本重构)

做法 代码片段 说明
4. Setter/Field 注入 @Autowired lateinit var b: B 让 Spring 能用三级缓存
5. @Lazy 延迟注入 @Lazy @Autowired val b: B 注入代理对象,真正用时才创建
6. 方法参数注入 fun doIt(b: B) 只在方法内部用,避免字段级循环
7. 抽工具类 把公共逻辑放到 @Component Util 两个 Service 都依赖 Util,而非彼此

3. 配置层(不改业务代码)

做法 配置示例 适用场景
8. ObjectProvider / Provider ObjectProvider<B> bProvider 运行时按需取,打破字段级循环
9. @Configuration 手动装配 @Bean fun a(b: B) = A(b) 构造器循环时显式控制顺序
10. 调整作用域 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 多例 Bean 循环,但会牺牲单例语义

4. 兜底方案(Spring 自动)

做法 说明 风险
11. 保持默认三级缓存 什么都不改 仅对单例+Setter/Field 有效
12. 允许循环依赖(Spring Boot 2.6+) spring.main.allow-circular-references=true 官方不推荐,升级可能失效

面试 15 秒总结

真正解决循环依赖,优先做领域拆分或事件驱动;

代码层面用 @Lazy / ObjectProvider / Setter 注入即可 90% 场景无痛落地;

构造器循环或多例 Bean 只能重构,Spring 的三级缓存只是兜底,不是银弹。

相关推荐
Joy T2 小时前
Agent 确定性上下文设计:从 Prompt 参数注入到能力分层
java·开发语言·微服务·架构·prompt·agent context
m0_587383005 小时前
广州 24 小时自助健身房解决方案技术实现与实战指南
java·spring·小程序·架构·需求分析
·云扬·5 小时前
Prompt 工程与安全:从 System 设计到注入防御
java·人工智能·安全·ai·prompt
代码不停6 小时前
自动化测试(java)
java·开发语言·selenium·自动化
行百里er6 小时前
Redis 完结篇——Redis 热点问题在 Spring Boot 项目中实战
redis·后端
唠点键盘之外的7 小时前
26 向量数据库实战:从 0 搭一条能用的检索链路(pgvector + Spring AI)
数据库·人工智能·spring
高频因子挖掘机7 小时前
只取最近 60 个交易日,却每次拉全历史:量化脚本变慢的原因与改法
后端·github·api
鬼手点金8 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github
孟健8 小时前
从5000亿Token到83%字节匹配:AI逆向工程与重构的工程闭环实践
后端·架构·ai编程
paopaokaka_luck9 小时前
滑雪场管理系统(AI智能助手流式对话,ECharts 运营数据分析、教练、雪具与场地一体化预约,钱包支付退款、订单核销与服务评价)
java·人工智能·spring boot·网络协议·数据分析·echarts