
Spring 2.7 循环依赖问题现象
很多同学在面试中被问到Spring循环依赖的处理机制,尤其是Spring 2.7版本后三级缓存的变化。实际开发中,如果遇到启动时直接报BeanCurrentlyInCreationException,大概率是出现了Spring无法解决的循环依赖。比如A依赖B,B又依赖A,这种场景下Spring 2.7的处理逻辑值得深挖。
典型的报错信息会提示:"Requested bean is currently in creation: Is there an unresolvable circular reference?",这说明你的Bean定义已经超出了Spring的解决能力范围。
Spring 2.7 循环依赖的解决机制
Spring的循环依赖解决机制核心在于三级缓存:
- 一级缓存(单例池):存放初始化完成的Bean
- 二级缓存(早期暴露对象):存放半成品Bean(完成实例化但未初始化)
- 三级缓存(Bean工厂):存放Bean工厂对象,用于生成代理对象
Spring 2.7版本中,三级缓存的变化主要针对代理对象的处理。当两个Bean互相依赖时,Spring会通过提前暴露对象引用的方式打破僵局。例如,A实例化后会先放入三级缓存,此时B开始实例化并发现需要A,Spring会通过三级缓存中的工厂对象生成A的代理,从而完成B的创建,最后再补全A的初始化。

Spring 2.7 循环依赖的源码解析
如果想在面试中脱颖而出,必须了解源码中DefaultSingletonBeanRegistry类的核心逻辑。重点关注这三个方法:
getSingleton():从缓存中获取BeanaddSingletonFactory():向三级缓存添加Bean工厂getEarlyBeanReference():处理代理对象
重点逻辑:当Bean A依赖Bean B时,A实例化后会被放入三级缓存;此时B开始创建,发现需要A,就会触发三级缓存的工厂对象生成A的早期引用,从而避免循环依赖的死锁。
Spring 2.7 循环依赖的排查技巧
遇到循环依赖问题时,可以按以下步骤排查:
- 检查Bean的依赖关系:用IDEA的依赖图工具快速定位
- 查看启动日志:Spring会明确提示无法解决的循环依赖链
- 调整Bean加载顺序:通过
@DependsOn强制指定初始化顺序 - 使用Setter注入替代构造器注入:Spring只能解决通过Setter或字段注入的循环依赖
如果大家需要购买面试鸭会员,可以通过面试鸭返利网找到我,返利25元!
循环依赖的典型踩坑场景
1. 构造器注入引发的死锁
Spring无法解决构造器注入的循环依赖。例如:
@Component
public class A {
private final B b;
public A(B b) { this.b = b; }
}
@Component
public class B {
private final A a;
public B(A a) { this.a = a; }
}
这种情况必须重构代码,改用Setter注入。
2. 多线程环境下的代理问题
如果Bean被代理(如@Async或@Transactional),可能因为代理对象生成时机导致循环依赖失效。这时需要确认是否启用了正确的代理模式(CGLIB或JDK动态代理)。
高频面试问题参考答案
Q:Spring能解决哪些类型的循环依赖?
A:只能解决通过Setter或字段注入的单例Bean的循环依赖,构造器注入和多例Bean不适用。
Q:三级缓存的具体作用是什么?
A:一级缓存存成品Bean,二级缓存存半成品Bean,三级缓存存Bean工厂。核心目的是延迟处理代理对象,防止重复创建。
Q:Spring 2.7在循环依赖处理上有哪些改进?
A:优化了代理对象的生成策略,减少不必要的工厂调用,同时提升了循环依赖检测的准确性。

如果你正在准备Java面试,记得领取2025年Java面试宝典。通过面试鸭返利网购买会员还能省25元,性价比超高!


