@Component public class A { @Autowired private B b; }
@Component public class B { @Autowired private A a; }
上面的情况就是 循环依赖
Bean的创建初始化过程如下
如果不采取措施,那么循环依赖就会进入死循环
但 Spring 已经帮我们解决了大部分循环依赖问题
具体是如何解决的?
Spring解决循环依赖是通过三级缓存,对应的三级缓存如下所示:
缓存名称 |
源码名称 |
作用 |
一级缓存 |
singletonObjects |
单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象 |
二级缓存 |
earlySingletonObjects |
缓存早期的bean对象(生命周期还没走完) |
三级缓存 |
singletonFactories |
缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的 |
下图是Bean的生命周期,我们依照Bean的生命周期来说明,关于Bean的生命周期可以参考我的另外一篇博客
一级缓存 存放 已经全部完成的Bean,可以直接使用
二级缓存 存放 早期的bean对象,其生命周期还没走完,也就是仅通过构造函数创建出实例,但未进行依赖注入及其以下初始化步骤
三级缓存 存放 对象工厂,对象工厂用于创建对象,其具体作用下面会说明
实际上 一级 和 二级 缓存就能解决一般的 循环依赖问题
但是 如果一个对象被增强了,即 是个代理对象, 这个时候就需要一个三级缓存
但是 仍有些循环引用 Spring 解决不了,这时候需要手动解决,最典型的就是 构造方法出现了循环依赖,如下
@Component public class A { // B成员变量 private B b; public A(B b){ System.out.println("A的构造方法执行了..."); this.b = b ; } }
@Component public class B { // A成员变量 private A a; public B(A a){ System.out.println("B的构造方法执行了..."); this.a = a ; } }
解决办法 -- 延迟加载:
1. public A(@Lazy B b){ 2. System.out.println("A的构造方法执行了..."); 3. this.b = b ; 4. }