循环引用举例
@Component("beanA")
public class BeanA {
@Autowired
private BeanB beanB;
}
@Component("beanB")
public class BeanB {
@Autowired
private BeanA beanA;
}
以上就是典型的循环引用场景。
熟悉Spring的人都知道Spring是通过三级缓存来处理循环依赖:
/** Cache of singleton objects: bean name --> bean instance */
// 一级缓存 Spring容器中所有的单例bean,这也是狭义的IOC容器
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);
下面是本次跟踪的大概流程,主要是关注了三级缓存的变化情况
用大白话来描述一下流程(假定beanA先创建):
Code1:
从Spring真正开始创建对象的doGetBean
方法开始
protected T doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 尝试从一、二、三级缓存中获取beanA,跳到Code2
Object sharedInstance = getSingleton(beanName);
// 省略 ....
if (mbd.isSingleton()) {
// Code1.1 由于上面获取不到beanA,此处开始创建beanA,跳到Code3
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
// 省略 ....
return (T) bean;
}
Code2:
此时,由于beanA第一次被创建,因此一级缓存
获取不到对象,返回NULL,再次返回Code1创建beanA
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从一级缓存中获取beanA,此时是获取不到的
Object singletonObject = this.singletonObjects.get(beanName);
// 由于beanA不是正在创建的对象,因此if判断进不去,不会尝试去二、三级缓存加载bean
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 省略 ...
}
return singletonObject; // 返回null 跳回Code1.1
}
Code3:(注意这里重载了Code2的方法)
首先从一级缓存中尝试获取beanA,如果获取不到则标记当前beanA处于创建状态,通过ObjectFactory
开始创建beanA
public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
synchronized (this.singletonObjects) {
// 从一级缓存获取bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 省略 ...
// 这里标记beanA已经开始创建
beforeSingletonCreation(beanName);
// 省略 ...
try {
// 通过ObjectFactory创建对象 跳向Code4
singletonObject = singletonFactory.getObject();
newSingleton = true;
} finally {
// 省略 ...
// 将beanA从正在创建的集合中移除
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 将beanA从二级缓存earlySingletonObjects中移除
// 添加到一级缓存singletonObjects
// 这个方法会统一将二三级缓存挪动到一级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject; // 到此一个循环引用的对象创建成功返回 END
}
Code4:
首先通过推断出来的构造器创建beanA,接着将beanA放入三级缓存,开始为beanA填充属性,此时会发现beanB尚未创建,进入beanB的创建流程
beanA填充beanB属性完毕,从一、二级缓存中尝试获取缓存中的beanA
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd,
final @Nullable Object[] args) throws BeanCreationException {
// 此处通过构造器反射创建Bean对象,
// 到此beanA已经创建出来,但是没有属性填充
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
// 判断是否可以当前被创建的对象是否可以提前暴露
// 条件:单例对象、正在被创建、允许循环引用
boolean earlySingletonExposure = (mbd.isSingleton()
&& this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 在这里将beanA放入到了三级缓存singletonFactories中
addSingletonFactory(beanName,
() -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 此处beanA已经创建成功,开始填充beanA的属性beanB,
// 创建beanB和beanA的逻辑差不多,跳到 Code5
populateBean(beanName, mbd, instanceWrapper);
// 填充完bean对象的属性,开始执行初始化操作
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
// 省略
}
// Code4.1 这里的if判断会进去,此时beanA已经填充了beanB
if (earlySingletonExposure) {
// 重新从一、二级缓存中获取beanA 跳到Code9
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 省略 ...
}
}
// 省略 ...
return exposedObject; // Code4.2 返回创建成功的beanA,返回Code3.1处
}
Code5:
创建beanB的流程其实类似上面创建beanA的流程,首先在一、二、三级缓存中没有找到beanB,则开始创建beanB
protected T doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 尝试从一、二、三级缓存获取beanB,就是Code2的逻辑,
// 此时是获取不到beanB的
Object sharedInstance = getSingleton(beanName);
// 省略 ....
// Create bean instance.
if (mbd.isSingleton()) {
// 由于上面获取不到beanB,此处开始创建beanB,跳到Code6
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
// 省略 ....
return (T) bean;
}
Code6:
这个其实就上面创建beanA的时候执行过得Code2,先从一级缓存获取beanB,没有获取到则标记beanB正在创建,进入创建beanB的流程
beanB经历实例化、属性填充、初始化
操作之后,清除beanB正在创建标记,并将beanB从三级缓存
挪到一级缓存
public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
synchronized (this.singletonObjects) {
// 从一级缓存获取beanB
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 省略 ...
// 这里标记beanB已经开始创建
beforeSingletonCreation(beanName);
// 省略 ...
try {
// 利用ObjectFactory创建beanB对象,跟Code4一样,
// 将beanB放入三级缓存singletonFactories,
// 并且开始尝试获取beanA注入beanB,跳向Code7
singletonObject = singletonFactory.getObject();
newSingleton = true;
} finally {
// 省略 ...
// Code6.1 将beanB从装在创建的集合中移除
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 将beanB从三级缓存singletonFactories中移除,
// 加入到一级缓存singletonObjects
// 这个方法会统一将二三级缓存挪动到一级缓存
addSingleton(beanName, singletonObject);
}
}
// 返回创建完毕的beanB给beanA 返回Code4.1处
return singletonObject;
}
}
Code7:
这里与创建beanA过程的Code4一样,创建beanB完毕之后,开始为beanB填充属性beanA
为beanB填充完毕beanA,beanB的创建过程主要步骤(实例化、属性填充、初始化
)结束
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd,
final @Nullable Object[] args) throws BeanCreationException {
// 省略beanB对象的创建过程...
// 在这里将beanB放入到了三级缓存singletonFactories中
boolean earlySingletonExposure = (mbd.isSingleton()
&& this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName,
() -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 此处beanB已经创建成功,开始填充beanB的属性beanA,跳到 Code8
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
// 省略
}
// 省略 ...
// Code 7.1 beanB成功装配了beanA属性,beanB创建过程完毕,
// 返回Code6.1处
return exposedObject;
}
Code8:
为beanB填充属性beanA的时候,Spring再次尝试创建beanA,此时会走到Code1的流程,但是此时Spring已经可以从三级缓存中获取到beanA,因此不会再往下执行beanA的创建,同时会将beanA从三级缓存
移动到二级缓存
PS.
经过beanA和beanB的创建,我们发现Spring每次创建一个bean都会尝试先去一、二、三级缓存
获取,这里其实就是Code2中getSingleton
,如果一级缓存没有获取到,但是bean正在被创建则尝试去二级缓存获取,二级缓存没有获取到,但是bean允许提前引用则再次尝试从三级缓存获取
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从一级缓存中获取beanA,此时是获取不到的
Object singletonObject = this.singletonObjects.get(beanName);
// 此时beanA已经被标记为正在创建的对象,因此这次if判断可以进去
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 此时二级缓存中不存在beanA
singletonObject = this.earlySingletonObjects.get(beanName);
// 此处allowEarlyReference为true,因此这个if判断会进去
if (singletonObject == null && allowEarlyReference) {
// 从三级缓存中获取到beanA
ObjectFactory> singletonFactory
= this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 将beanA从三级缓存中移除,加入到二级缓存
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
// 从三级缓存中获取到beanA,此时beanB就能正常的获取到beanA进行装配,
// 返回到Code7的Code7.1处
return singletonObject;
}
Code9:
beanA经历创建、属性填充、初始化
完毕,重新尝试从缓存中获取
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从一级缓存中获取beanA,此时是获取不到的
Object singletonObject = this.singletonObjects.get(beanName);
// 此时beanA已经被标记为正在创建的对象,因此这次if判断可以进去
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从二级缓存中获取到beanA
singletonObject = this.earlySingletonObjects.get(beanName);
// 此处allowEarlyReference为false,因此这个if判断进不去
if (singletonObject == null && allowEarlyReference) {
// 省略 ...
}
}
}
return singletonObject; // 返回beanA 回到Code4.2处
}
Spring为什么要使用三级缓存来解决循环依赖,而不使用二级缓存?
从上面解决循环引用的问题,我们可以总结出,Spring创建对象、装配属性的时候都尝试先从一、二、三级缓存加载创建好的对象,在装配属性的时候如果从三级缓存获取到对象,会移动到二级缓存,此后获取这个对象就会先从二级缓存中获取。
如果采用二级缓存,单纯从解决循环引用的角度来说确实可以实现,就以上面的beanA来说,假设beanB通过二级缓存装配了beanA属性,后续beanA被某些操作重新包装了一次再次放入二级缓存,就会导致同一个beanA属性,在不同的bean中引用了不同的对象。