SpringBoot 循环依赖解决方案
2026/6/3 22:39:10 网站建设 项目流程

循环依赖:两个或多个 Bean 互相注入(A依赖B,B依赖A),Spring 默认只能解决单例 Bean 的 setter/字段注入循环依赖,构造器注入、多例、代理场景会直接报错。

我会分场景+解决方案,从最简单到最复杂讲清楚。


一、先判断:你的循环依赖属于哪种?

1. 最常见:单例 Bean + 字段/setter 注入(无报错)

Spring自动解决,无需处理。

@ServicepublicclassA{@AutowiredprivateBb;// 字段注入}@ServicepublicclassB{@AutowiredprivateAa;}

正常运行,Spring 三级缓存天然支持。


2. 构造器注入循环依赖(必报错)

这是最常见的报错场景

@ServicepublicclassA{// 构造器注入 A 依赖 BpublicA(Bb){}}@ServicepublicclassB{// 构造器注入 B 依赖 ApublicB(Aa){}}

❌ 报错:Requested bean is currently in creation

解决方案(3种最优解)
方案1:改用字段/@Autowired 注入(最简单)

直接把构造器注入改成字段注入,Spring 自动解决。

方案2:使用@Lazy懒加载(推荐)

在构造器参数上加@Lazy,创建临时代理对象,打破循环:

@ServicepublicclassA{publicA(@LazyBb){// 关键:@Lazythis.b=b;}}@ServicepublicclassB{publicB(Aa){this.a=a;}}
方案3:使用ApplicationContext手动获取 Bean
@ServicepublicclassAimplementsApplicationContextAware{privateBb;@OverridepublicvoidsetApplicationContext(ApplicationContextctx){this.b=ctx.getBean(B.class);// 手动获取}}

3. 多例(prototype)Bean 循环依赖(必报错)

Spring不解决多例循环依赖,无三级缓存支持。

解决方案
  1. 放弃多例:改成单例(90%场景适用)
  2. 手动创建对象:不用 Spring 管理依赖
  3. 使用Provider延迟注入
@Component@Scope("prototype")publicclassA{@AutowiredprivateObjectProvider<B>bProvider;publicBgetB(){returnbProvider.getObject();}}

4. 代理类导致的循环依赖(AOP/事务)

开启 AOP/@Transactional后,Bean 被代理,默认三级缓存会失效,报错。

解决方案
方案1:启动类加配置(最省事)
@SpringBootApplicationpublicclassApp{publicstaticvoidmain(String[]args){// 允许循环依赖System.setProperty("spring.main.allow-circular-references","true");SpringApplication.run(App.class,args);}}
方案2:yml 配置
spring:main:allow-circular-references:true

5. 终极方案:重构代码(最规范,推荐)

循环依赖本质是代码设计不合理,最好从根源解决:

  1. 抽取公共类:把 A、B 共用逻辑抽到 C,A、B 都依赖 C
  2. 使用事件/观察者模式:解耦互相依赖
  3. 使用方法调用:不用注入 Bean,直接调用方法

示例(抽取公共类):

// 公共逻辑@ServicepublicclassC{}@ServicepublicclassA{@AutowiredprivateCc;}@ServicepublicclassB{@AutowiredprivateCc;}

✅ 彻底消除循环依赖,代码更优雅。


二、快速排查工具

如果你不知道哪里循环依赖,开启日志:

logging:level:org.springframework:DEBUG

日志会打印完整依赖链,直接定位报错 Bean。


三、总结:按场景选择方案

依赖场景是否报错解决方案
单例+字段注入无需处理
构造器注入@Lazy/ 字段注入
多例Bean改单例 /ObjectProvider
AOP/事务代理开启allow-circular-references
所有场景-重构代码(最优)

核心记住

  1. Spring只自动解决单例+字段/setter 注入的循环依赖
  2. 构造器注入用@Lazy最快解决
  3. 生产环境优先重构代码,不要依赖配置强行开启循环依赖

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询