@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的生命周期可以参考我的另外一篇博客
http://t.csdn.cn/DZz5zhttp://t.csdn.cn/DZz5z
一级缓存 存放 已经全部完成的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 ;
}
}
解决办法 -- 延迟加载:
public A(@Lazy B b){
System.out.println("A的构造方法执行了...");
this.b = b ;
}