循环依赖的概念
循环依赖指的是两个或多个Bean相互依赖,形成闭环。例如Bean A依赖Bean B,Bean B又依赖Bean A,导致Spring无法正常初始化这些Bean。Spring Boot默认情况下会检测并抛出BeanCurrentlyInCreationException异常。
使用构造器注入的解决方案
构造器注入是Spring推荐的依赖注入方式,但构造器注入无法直接解决循环依赖问题。需要通过以下方式调整:
- 将部分依赖改为Setter注入 或字段注入,延迟依赖的解析。
- 使用
@Lazy注解,延迟加载其中一个Bean,打破初始化时的循环。
示例代码:
java
@Service
public class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
使用Setter或字段注入
通过Setter或字段注入可以避免构造器注入的严格初始化顺序问题:
java
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
配置Spring Boot允许循环依赖
在Spring Boot 2.6及以上版本中,默认禁止循环依赖。可以通过配置调整:
properties
spring.main.allow-circular-references=true
重构设计避免循环依赖
- 提取公共逻辑到第三个Bean中,解除直接循环。
- 使用事件驱动(
ApplicationEventPublisher)解耦Bean间的直接调用。 - 将依赖关系改为单向依赖,例如通过接口隔离。
使用@DependsOn明确初始化顺序
通过@DependsOn强制指定Bean的初始化顺序,但需谨慎使用:
java
@Service
@DependsOn("serviceB")
public class ServiceA {
// ...
}
关键注意事项
- Spring Boot 2.6+默认禁止循环依赖,优先考虑重构设计。
@Lazy注解适用于临时解决方案,但可能掩盖设计问题。- 循环依赖可能导致难以维护的代码,建议通过模块化设计规避。