一、什么是循环依赖?
例如,就是A对象依赖了B对象,B对象依赖了A对象。
// A依赖了B
class A{
public B b;
}
// B依赖了A
class B{
public A a;
}
如果不考虑Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的事情。
比如:
A a = new A();
B b = new B();
a.b = b;
b.a = a;
这样,A,B就依赖上了。
但是,在 Spring 中循环依赖就是一个问题了,因为,在 Spring 中,一个对象并不是简单 new 出来了,而是会经过一系列的 Bean 的生命周期,就是因为 Bean 的生命周期所以才会出现循环依赖问题。当然,在 Spring 中,出现循环依赖的场景很多,有的场景 Spring 自动帮我们解决了,而有的场景则需要程序员来解决。
要明白Spring中的循环依赖,得先明白Spring中Bean的生命周期。
二、Bean的生命周期
2.1 Spring Bean 的生命周期
具体看这篇博客–》 Spring Bean 的生命周期
2.2 Bean 的生成步骤
被 Spring 管理的对象叫做 Bean 。Bean的生成步骤如下:
Spring 扫描 class 得到 BeanDefinition;
根据得到的 BeanDefinition 去生成 bean;
首先根据 class 推断构造方法;
根据推断出来的构造方法,反射,得到一个对象(暂时叫做原始对象);
填充原始对象中的属性(依赖注入);
如果原始对象中的某个方法被 AOP 了,那么则需要根据原始对象生成一个代理对象;
把最终生成的代理对象放入单例池(源码中叫做 singletonObjects)中,下次 getBean 时就直接从单例池拿即可;
对于 Spring 中的 Bean 的生成过程,步骤还是很多的,并且不仅仅只有上面的7步,还有很多很多,这里不详细说了。
我们可以发现,在得到一个原始对象后,Spring 需要给对象中的属性进行依赖注入,那么这个注入过程是怎样的?
比如上文说的 A 类,A 类中存在一个 B 类的 b 属性,所以,当 A 类生成了一个原始对象之后,就会去给 b 属性去赋值,此时就会根据 b 属性的类型和属性名去 BeanFactory 中去获取 B 类所对应的单例bean。
1. 如果此时 BeanFactory 中存在 B 对应的 Bean,那么直接拿来赋值给 b 属性;
2. 如果此时 BeanFactory 中不存在 B 对应的 Bean,则需要生成一个 B 对应的 Bean,然后赋值给 b属性。
问题就出现在「第二种」情况,如果此时 B 类在 BeanFactory 中还没有生成对应的 Bean,那么就需要去生成,就会经过 B 的 Bean 的生命周期。
那么在创建 B 类的 Bean 的过程中,如果 B 类中存在一个 A 类的 a 属性,那么在创建 B 的 Bean 的过程中就需要 A 类对应的 Bean,但是,触发 B 类 Bean 的创建的条件是 A 类 Bean 在创建过程中的依赖注入,所以这里就出现了循环依赖:
A Bean创建–>依赖了 B 属性–>触发 B Bean创建—>B 依赖了 A 属性—>需要 A Bean(但A Bean还在创建过程中)
从而导致 A Bean 创建不出来,B Bean 也创建不出来。
这是循环依赖的场景,但是上文说了,在 Spring 中,通过某些机制帮开发者解决了部分循环依赖的问题,这个机制就是「三级缓存」。
三、三级缓存
一级缓存为:singletonObjects;
二级缓存为:earlySingletonObjects;
三级缓存为:singletonFactories;
/** Cache of singleton objects: bean name –> bean instance */
private final Map singletonObjects = new ConcurrentHashMap(256);
/** Cache of singleton factories: bean name –> ObjectFactory */
private final Map> singletonFactories = new HashMap>(16);
/** Cache of early singleton objects: bean name –> bean instance */
private final Map earlySingletonObjects = new HashMap(16);
3.1三个缓存分别有什么作用
「singletonObjects」中缓存的是已经经历了完整生命周期的bean对象。
「earlySingletonObjects」比 singletonObjects 多了一个 early ,表示缓存的是早期的 bean对象。早期指的是 Bean 的生命周期还没走完就把这个 Bean 放入了 earlySingletonObjects。
「singletonFactories」中缓存的是 ObjectFactory,表示对象工厂,用来创建某个对象的。
|