Spring Boot 2.6+ 构造器注入循环依赖默认启动失败,因构造器需完整实例而双方互等;推荐优先使用@Lazy延迟一方依赖解析,其次改为字段/Setter注入,最后可手动通过ApplicationContext获取。

构造器注入时出现循环依赖,Spring Boot 2.6+ 默认直接启动失败,报错类似 Requested bean is currently in creation。这不是配置问题,而是设计层面的硬性限制——构造器必须拿到完整实例才能执行,A 等 B、B 等 A,谁也动不了。改法核心就一条:**打破“双方都急着要对方实例”的僵局**。下面几种方式按推荐度排序,实操性强、风险低、符合 Spring 哲学。
用 @Lazy 延迟其中一个依赖的解析
这是最轻量、最推荐的救急改法,不改结构、不降可测性,只加一个注解:
- 选 A 或 B 中任意一个类,在其构造器参数上加
@Lazy - Spring 不再尝试立即创建被
@Lazy标记的 Bean,而是注入一个代理对象 - 真正调用该 Bean 的方法时,才触发它的初始化,此时另一个 Bean 已存在
示例(ServiceA 构造器中延迟 ServiceB):
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
把构造器注入改成字段或 Setter 注入
如果业务逻辑允许,这是最彻底的“回归默认支持”的方式。Spring 的三级缓存机制天然支持单例 Bean 的字段/Setter 循环依赖:
- 删掉构造器,用
@Autowired直接标注字段,或写一个@Autowired的 setter 方法 - 无需额外配置,启动即过
- 注意:字段注入会削弱不可变性和测试友好性,适合内部服务或过渡期快速修复
示例(字段注入):
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
用 ApplicationContext 手动获取依赖
当上述两种都不适用(比如必须保持构造器、又不能加 @Lazy),可退一步在运行时按需取 Bean:
- 让类实现
ApplicationContextAware接口 - 在需要使用对方 Bean 的地方,调用
context.getBean(Xxx.class) - 相当于把依赖时机从“创建时”挪到“首次使用时”,效果类似
@Lazy,但更显式、可控
注意:这种方式绕过了 Spring 的依赖注入管理,单元测试时需手动 mock 上下文,维护成本略高。
不建议的改法:开全局开关
配置 spring.main.allow-circular-references=true 虽能启动,但有明显缺陷:
- 仅对字段/Setter 注入有效,构造器注入仍会失败
- 掩盖设计问题,可能引发 NPE 或未初始化状态调用
- 不符合 Spring Boot 2.6+ 的默认安全策略,上线环境通常禁用


















