2025年Java面试宝典网盘地址
提取码:9b3g(建议保存备用,涵盖大厂高频考点)
spring bean如果出现循环依赖如何解决

什么是Spring Bean循环依赖?
循环依赖就是两个或多个Bean相互引用,比如A依赖B,B又反过来依赖A,形成"鸡生蛋蛋生鸡"的死循环。这种情况会导致Spring容器在初始化时抛出BeanCurrentlyInCreationException,直接影响项目启动。
面试官特别喜欢问这个问题,因为它既考察IOC容器底层机制,又涉及实际开发经验。
Spring如何解决循环依赖?
三级缓存机制
Spring通过三级缓存来破解这个困局:
- 一级缓存(单例池):存放完全初始化好的Bean
- 二级缓存(早期曝光对象):存放半成品Bean(已实例化但未初始化)
- 三级缓存(工厂缓存):存放Bean工厂对象
具体处理流程分三步走:
- 创建A时先往三级缓存注册工厂
- 填充属性发现需要B,触发B的创建
- B在填充属性时又从三级缓存拿到A的早期引用

关键点:必须是单例+属性注入
这里有个重要前提——必须使用属性注入方式。如果是构造器注入,Spring也无能为力,因为要创建Bean必须先完成构造器调用,而构造参数中的依赖此时还未创建。
哪些情况解决不了?
1. 构造器注入死局
// 这种写法会导致启动失败
@Service
public class A {
private final B b;
public A(B b) { this.b = b; }
}
@Service
public class B {
private final A a;
public B(A a) { this.a = a; }
}
2. AOP代理的陷阱
如果循环依赖的Bean需要生成代理对象(比如@Async、@Transactional等场景),必须保证:
- 使用CGLIB代理(默认已支持)
- 不要强制指定为JDK动态代理
3. @DependsOn连环套
当通过@DependsOn手动指定依赖顺序时,如果形成循环链,Spring会直接拒绝创建。
开发中的避坑指南
- 尽量避免循环依赖:出现循环依赖往往意味着设计有问题,推荐使用ApplicationContext.getBean()延迟获取
- 使用@Lazy注解:在注入点添加@Lazy,让依赖变成延迟加载
- 接口分离原则:将公共方法抽到单独接口,减少直接耦合
- 架构审查:定期用SonarQube等工具检测循环依赖

高频面试考点
- 三级缓存各自存什么?为什么需要三级而不是两级?
- 原型(prototype)作用域的Bean能否解决循环依赖?为什么?
- Spring Boot中如何处理循环依赖?和Spring Framework处理方式有何不同?
- 如何快速定位项目中的循环依赖?
如果大家在准备面试时需要购买面试鸭会员,可以通过面试鸭返利网联系我,可享25元专属返利。更多技术干货可以下载开头的面试宝典,覆盖最新大厂真题。


