Spring Boot 3.1.5使用Setter/Field Injection仍遇循环依赖问题求助
循环依赖问题排查与解决方案(Java17 + Spring Boot 3.1.5)
原本预期Setter注入或Field注入可解决循环依赖,但在Java17 + Spring Boot 3.1.5项目中,两种方式均触发循环依赖错误,以下是相关代码、报错信息、项目结构及解决方案:
1. 注入方式代码示例
Setter注入
BeanA
@Component public class BeanA { BeanA() { System.out.println("BeanA constructor called !!!"); } private BeanB beanB; @Autowired public void setBeanB(BeanB beanB) { System.out.println("Setting property beanB of BeanA instance"); this.beanB = beanB; } }
BeanB
@Component public class BeanB { BeanB() { System.out.println("BeanB constructor called !!!"); } private BeanA beanA; @Autowired public void setBeanA(BeanA beanA) { System.out.println("Setting property beanA of BeanB instance"); this.beanA = beanA; } }
Field注入
BeanA
@Component public class BeanA { @Autowired BeanB beanB; BeanA(){ // System.out.println("beanA init!"); } }
BeanB
@Component public class BeanB { @Autowired BeanA beanA; BeanB(){ System.out.println("beanB init!"); } }
2. 报错信息
************************** APPLICATION FAILED TO START *************************** Description: The dependencies of some of the beans in the application context form a cycle: ┌─────┐ | beanA ↑ ↓ | beanB └─────┘ Action: Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
3. 项目结构
com.demo.example ├── MainApp.java ├── setterInjection │ ├── BeanA.java │ └── BeanB.java └── fieldInjection ├── BeanA.java └── BeanB.java
解决方案
原因说明
Spring Boot 2.6及以上版本默认禁用了循环依赖,即使Setter/Field注入这类原本Spring可处理的循环依赖场景,也会被默认拦截报错。
方案1:临时开启循环依赖允许(应急用)
在application.properties中添加配置:
spring.main.allow-circular-references=true
或在application.yml中添加:
spring: main: allow-circular-references: true
注意:此方案仅作为临时应急手段,Spring官方不推荐长期依赖,会增加代码维护复杂度。
方案2:重构代码打破循环依赖(推荐)
方式1:提取公共逻辑到独立Bean
将BeanA和BeanB互相依赖的业务逻辑,抽离为一个新的组件(比如CommonService),让BeanA和BeanB都依赖这个新组件,消除互相依赖关系。
示例:
@Component public class CommonService { // 原BeanA和BeanB共享的逻辑 } @Component public class BeanA { private final CommonService commonService; public BeanA(CommonService commonService) { this.commonService = commonService; } } @Component public class BeanB { private final CommonService commonService; public BeanB(CommonService commonService) { this.commonService = commonService; } }
方式2:使用@Lazy延迟初始化依赖
给其中一个Bean的依赖添加@Lazy注解,让Spring在第一次实际使用该依赖时才初始化,而非启动阶段强制创建,从而避开循环依赖检查。
示例(Setter注入场景):
@Component public class BeanA { private BeanB beanB; @Autowired public void setBeanB(@Lazy BeanB beanB) { this.beanB = beanB; } }
示例(Field注入场景):
@Component public class BeanA { @Autowired @Lazy BeanB beanB; }
方式3:使用@DependsOn指定初始化顺序
通过@DependsOn注解强制指定Bean的初始化顺序,让其中一个Bean先完成初始化,再创建另一个Bean。
示例:
@Component @DependsOn("beanB") public class BeanA { private BeanB beanB; @Autowired public void setBeanB(BeanB beanB) { this.beanB = beanB; } }
注意:此方式需确保业务逻辑允许该初始化顺序,避免出现未初始化的依赖调用问题。
内容的提问来源于stack exchange,提问作者clorzs
相关产品推荐
相关产品推荐

