最近看源碼在研究類似如下配置的循環(huán)依賴是怎么解決的?
<bean id="a" class="com.project.demo.A" scope="singleton">
<property name="b" ref="b"/>
</bean>
<bean id="b" class="com.project.demo.B" scope="singleton">
<property name="a" ref="a"/>
</bean>
說明:
1、Spring容器解決循環(huán)依賴的問題配置類必須是單例模式scope="singleton"才支持,如果是scope="prototype"是無法解決循環(huán)依賴的。
2、Spring容器解決循環(huán)依賴主要依靠三級(jí)緩存機(jī)制
2.1 一級(jí)緩存使用的map: private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
2.2 二級(jí)緩存使用的map: private final Map<String, Object> earlySingletonObjects = new HashMap(16);
2.3 三級(jí)緩存使用的map: private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
3、Spring容器解決循環(huán)依賴簡(jiǎn)潔概述主要有四大流程方法:獲取對(duì)象 getSingleton()、 創(chuàng)建對(duì)象(實(shí)例化) doCreateBean()、填充屬性(初始化) populateBean()、返回對(duì)象 addSingleton()
在系統(tǒng)啟動(dòng)獲取配置文件后,程序是依次讀取并加載的,所以上面配置文件代碼,先實(shí)例化a對(duì)象,然后初始化a對(duì)象給a添加b屬性,再實(shí)例化b對(duì)象,最后初始化b對(duì)象給添加屬性a.
那么在代碼執(zhí)行過程中,先調(diào)用getSingleton()方法,我們查看源碼
@Nullable
public Object getSingleton(String beanName) { // 調(diào)用下方重載方法
return this.getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 先從一級(jí)緩存中獲取a對(duì)象的實(shí)例
Object singletonObject = this.singletonObjects.get(beanName); // 如果從一級(jí)緩存中獲取不到a對(duì)象,那么檢查該對(duì)象是否正在被創(chuàng)建,如果正在被創(chuàng)建,則進(jìn)入if循環(huán)中
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) { // 從二級(jí)緩存中獲取該對(duì)象
singletonObject = this.earlySingletonObjects.get(beanName); // 如果二級(jí)緩存中無法獲取該對(duì)象,那么一定會(huì)進(jìn)入如下if方法,因?yàn)閍llowEarlyReference傳過來的時(shí)候就是true
if (singletonObject == null && allowEarlyReference) { // 從三級(jí)緩存中獲取該對(duì)象
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) { // 如果獲取到了該對(duì)象,就將三級(jí)緩存中的對(duì)象放到二級(jí)緩存中,并且將三級(jí)緩存中的對(duì)象刪除
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
從三面的源碼發(fā)現(xiàn),如果a第一次獲取,那么第9行的if語句為false,將直接放回為null,這時(shí)回到創(chuàng)建對(duì)象doCreateBean()方法,該方法使用反射的方式生成a對(duì)象,并且該對(duì)象在三級(jí)緩存中,對(duì)象生成后就需要對(duì)a對(duì)象進(jìn)行屬性填充:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// 省略多行代碼,大致就是調(diào)用各種方法,通過反射創(chuàng)建對(duì)象
try {
// a對(duì)象創(chuàng)建完成,調(diào)用屬性填充方法,對(duì)a進(jìn)行屬性填充
this.populateBean(beanName, mbd, instanceWrapper);
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}
if (earlySingletonExposure) {
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 省略多行代碼
}
}
// 省略多行代碼
}
在上面代碼doCreateBean()方法中先創(chuàng)建a對(duì)象,創(chuàng)建完成后會(huì)調(diào)用this.populateBean(beanName, mbd, instanceWrapper)方法對(duì)a進(jìn)行屬性填出,這個(gè)時(shí)候會(huì)獲取配置文件中所有<bean id="a">里面的所有屬性,發(fā)現(xiàn)會(huì)存在一個(gè)b屬性,下面貼出部分源碼
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
} else {
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
// 刪除大量代碼
}
if (continueWithPropertyPopulation) {
// 刪除大量源代碼,applyPropertyValues方法中beanName為a,pvs為狀態(tài)各種屬性的PropertyValues對(duì)象,pvs就裝有b這個(gè)屬性
if (pvs != null) {
this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
}
}
}
}
繼續(xù)跟進(jìn)applyPropertyValues方法的源碼
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (!pvs.isEmpty()) {
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl)bw).setSecurityContext(this.getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List original;
if (pvs instanceof MutablePropertyValues) {
// 省略大量代碼
} else {
original = Arrays.asList(pvs.getPropertyValues());
}
// 省略大量代碼 大致過程是將屬性對(duì)象pvs 轉(zhuǎn)化成original List對(duì)象,然后在使用迭代器在下面進(jìn)行迭代
Iterator var11 = original.iterator();
while(true) {
while(var11.hasNext()) {
PropertyValue pv = (PropertyValue)var11.next();
if (pv.isConverted()) {
deepCopy.add(pv);
} else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
// 通過下面方法解決依賴的b,整個(gè)方法在迭代器中,外層在while(true)中,可能有多個(gè)屬性,循環(huán)直到所有屬性都解決了就return;或者拋出異常
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
// 省略大量代碼
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
return;
} catch (BeansException var19) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var19);
}
}
}
}
繼續(xù)跟進(jìn)上面紅色方法
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference)value;
return this.resolveReference(argName, ref);
} else if (value instanceof RuntimeBeanNameReference) {
// 省略多行代碼
}
// 省略多行代碼
}
繼續(xù)跟進(jìn)紅色部分的代碼
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
String refName = ref.getBeanName();
refName = String.valueOf(this.doEvaluate(refName));
Object bean;
if (ref.isToParent()) {
// 省略多行代碼
} else {
// 通過refName的值b又去工廠找b對(duì)象
bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
}
// 省略多行代碼
return bean;
} catch (BeansException var5) {
throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, var5);
}
}
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
// 跟了這么就,最終表明在實(shí)例化a對(duì)象后,在裝載a的屬性b時(shí),會(huì)經(jīng)過各種校驗(yàn)最終到getSingleton(),及先獲取b對(duì)象,如果b對(duì)象不存在則會(huì)對(duì)b完成創(chuàng)建的過程
Object sharedInstance = this.getSingleton(beanName);
// 省略多行代碼
}
上面整個(gè)過程概括:在檢測(cè)到需要實(shí)例化a時(shí),先去獲取a對(duì)象,看a是否已經(jīng)存在,獲取去先從一級(jí)緩存中獲取,如果沒有并且如果a也沒有正在實(shí)例化,那么直接返回null,表明獲取不到a對(duì)象,那么此時(shí)調(diào)用doCreateBean()方法完成對(duì)a對(duì)象的實(shí)例化過程(通過反射創(chuàng)建a對(duì)象),并且將創(chuàng)建的a對(duì)象放在三級(jí)緩存中,然后繼續(xù)執(zhí)行doCreateBean中的populateBean()方法完成對(duì)a進(jìn)行初始化即添加屬性b,經(jīng)過一些列校驗(yàn),最終又會(huì)調(diào)用getSingleton()方法來獲取b對(duì)象,同樣會(huì)返回null,這個(gè)時(shí)候就會(huì)去執(zhí)行doCreateBean()方法創(chuàng)建b對(duì)象,同樣過反射創(chuàng)建b,當(dāng)b對(duì)象創(chuàng)建完成時(shí)也會(huì)存放在三級(jí)緩存中,在實(shí)例化b對(duì)象完成,然后繼續(xù)執(zhí)行doCreateBean中的populateBean()方法,也需要初始化b對(duì)象,填充b的屬性,這時(shí)發(fā)現(xiàn)b對(duì)象的屬性是a,同樣再次通過getSingleton()方法獲取a,獲取a的過程如第一個(gè)源碼部分,先從一級(jí)緩存中獲取,獲取不到,然后判斷a正在創(chuàng)建中,然后就從二級(jí)、三級(jí)緩存中獲取,最終在三級(jí)緩存中獲取到了a,并且將三級(jí)緩存中的a對(duì)象放到二級(jí)緩存中,并將刪除三級(jí)緩存中的a,此時(shí)b對(duì)象初始化也完成。
在a對(duì)象初始化的流程中,將b對(duì)象也實(shí)例化和初始化了,在b的初始化過程中,將a從三級(jí)緩存移到了二級(jí)緩存中,當(dāng)b初始化完成后繼續(xù)向下執(zhí)行,會(huì)執(zhí)行到addSingleton(),查看源碼
protected void addSingleton(String beanName, Object singletonObject) {
synchronized(this.singletonObjects) { // 將b加入到1級(jí)緩存
this.singletonObjects.put(beanName, singletonObject); // 將b從三級(jí)緩存中刪除
this.singletonFactories.remove(beanName); // 將b從二級(jí)緩存中刪除(b在二級(jí)緩存中沒有,即空刪除)
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
從上面代碼可以看出在,并創(chuàng)建完成并且初始化后,會(huì)將B從三級(jí)緩存中直接放到一級(jí)緩存中,并且刪除三級(jí)緩存中的數(shù)據(jù)。
所有b工作做完后返回到a初始化屬性b的代碼
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// 省略大量代碼
try {
// 完成a對(duì)于屬性b的檢查裝配工作后返回到方法populateBean(),繼續(xù)向下執(zhí)行
this.populateBean(beanName, mbd, instanceWrapper);
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}
if (earlySingletonExposure) {
// a執(zhí)行到該方法getSingleton(),這里面會(huì)將a從二級(jí)緩存中取出來
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 省略大量代碼
}
}
// 省略大量代碼
}
繼續(xù)執(zhí)行,最終也會(huì)到addSingleton()方法,將a也加入一級(jí)緩存,并且從二級(jí)緩存中刪除a。
這樣a和b兩個(gè)循環(huán)依賴的bean都被放入到一級(jí)緩存中。

最新2020整理收集的一些高頻面試題(都整理成文檔),有很多干貨,包含mysql,netty,spring,線程,spring cloud、jvm、源碼、算法等詳細(xì)講解,也有詳細(xì)的學(xué)習(xí)規(guī)劃圖,面試題整理等,
需要獲取這些內(nèi)容的朋友請(qǐng)加Q君樣:
11604713672