對於該問題,相信不少人面試中遇到過,原始碼也去看過,這裡我想說的是,看原始碼的方式。假設現在有a、b兩個類,a、b相互迴圈依賴,那麼我們就帶著這個問題去找單純的去看原始碼是毫無意義的,看完了就忘了,最多也只是零星記得有那麼些東西,我覺得要想做的真正理解還是要帶著問題去看。
首先getbean(a)必然回去例項化a,由於第一次建立a,那麼就不存在快取,直接進入abstractautowirecapablebeanfactory#docreatebean方法,也是建立bean的核心方法
protected object docreatebean(final string beanname, final rootbeandefinition mbd, final @nullable object args)
throws beancreationexception
} //獲取例項化物件的型別
if (beantype != nullbean.class)
// allow post-processors to modify the merged bean definition.
//呼叫postprocessor後置處理器
synchronized (mbd.postprocessinglock)
catch (throwable ex)
mbd.postprocessed = true;
}} // eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle inte***ces like beanfactoryaware.
//向容器中快取單例模式的bean物件,以防迴圈引用
boolean earlysingletonexposure = (mbd.issingleton() && this.allowcircularreferences &&
issingletoncurrentlyincreation(beanname));
if (earlysingletonexposure)
//這裡是乙個匿名內部類,為了防止迴圈引用,盡早持有物件的引用
addsingletonfactory(beanname, () -> getearlybeanreference(beanname, mbd, bean));
} // initialize the bean instance.
//bean物件的初始化,依賴注入在此觸發
//這個exposedobject在初始化完成之後返回作為依賴注入完成後的bean
object exposedobject = bean;
try
catch (throwable ex)
else
} if (earlysingletonexposure)
//當前bean依賴其他bean,並且當發生迴圈引用時不允許新建立例項物件
string dependentbeans = getdependentbeans(beanname);
setactualdependentbeans = new linkedhashset<>(dependentbeans.length);
//獲取當前bean所依賴的其他bean
for (string dependentbean : dependentbeans)
}if (!actualdependentbeans.isempty()) }}
} // register bean as disposable.
//註冊完成依賴注入的bean
try
catch (beandefinitionvalidationexception ex)
return exposedobject;
}
執行依賴注入之前會先執行addsinglefactory方法,將該bean對應的objectfactory新增到map> singletonfactories容器中,下邊執行依賴注入方法populatebean,因為我們a中有個b屬性,所以最終肯定是要去執行getbean(b) 的,同樣也會進入我們的docreatebean方法,也會執行populatebean想把a注入進來,這個時候會執行getbean(a),但是不會再走docreatebean方法了,會在一開始的defaultsingletonbeanregistry#getsingleton(string beanname)讀取快取,會使用我們singletonfactories中快取的a的singletonfactory.getobject()方法得到singletonobject,並且將該物件再放入另乙個快取當中mapearlysingletonobjects。到這裡,我們的b其實可以進行初始化了,但是b雖然注入了a,但是這個a是個原始物件,也就是a例項化之前注入到b的。
在b例項化之後來到外層的dogetbean方法
protected t dogetbean(final string name, @nullable final classrequiredtype,
@nullable final object args, boolean typecheckonly) throws bean***ception
else
}//獲取給定bean的例項物件,主要是完成factorybean的相關處理
//注意:beanfactory是管理容器中bean的工廠,而factorybean是
//建立建立物件的工廠bean,兩者之間有區別
bean = getobjectforbeaninstance(sharedinstance, name, beanname, null);
} else
// check if bean definition exists in this factory.
//對ioc容器中是否存在指定名稱的beandefinition進行檢查,首先檢查是否
//能在當前的beanfactory中獲取的所需要的bean,如果不能則委託當前容器
//的父級容器去查詢,如果還是找不到則沿著容器的繼承體系向父級容器查詢
beanfactory parentbeanfactory = getparentbeanfactory();
//當前容器的父級容器存在,且當前容器中不存在指定名稱的bean
if (parentbeanfactory != null && !containsbeandefinition(beanname))
else if (args != null)
else
}//建立的bean是否需要進行型別驗證,一般不需要
if (!typecheckonly)
try
//遞迴呼叫getbean方法,獲取當前bean的依賴bean
registerdependentbean(dep, beanname);
//把被依賴bean註冊給當前依賴的bean
getbean(dep);}}
// create bean instance.
//建立單例模式bean的例項物件
if (mbd.issingleton())
catch (bean***ception ex)
});//獲取給定bean的例項物件
bean = getobjectforbeaninstance(sharedinstance, name, beanname, mbd);
}//ioc容器建立原型模式bean例項物件
else if (mbd.isprototype())
finally
//獲取給定bean的例項物件
bean = getobjectforbeaninstance(prototypeinstance, name, beanname, mbd);
}//要建立的bean既不是單例模式,也不是原型模式,則根據bean定義資源中
//配置的生命週期範圍,選擇例項化bean的合適方法,這種在web應用程式中
else
try
finally
});//獲取給定bean的例項物件
bean = getobjectforbeaninstance(scopedinstance, name, beanname, mbd);
}catch (illegalstateexception ex) }}
catch (bean***ception ex)
}
這個方法比較長,我們主要關注建立單例這裡
if (mbd.issingleton())
catch (bean***ception ex)
});//獲取給定bean的例項物件
bean = getobjectforbeaninstance(sharedinstance, name, beanname, mbd);
}
這裡的defaultsingletonbeanregistry#getsingleton(string beanname, objectfactory<?> singletonfactory)裡面的addsingleton(beanname, singletonobject)會將earlysingletonobjects裡的物件放到singletonobjects裡面。至此,b已經例項化完畢了,並且存到了剛剛提到的這個容器裡面
這時候a會拿到例項化後的b進行依賴注入,初始化,而beanb最初拿到的原始物件指向的還是beana,隨著a被初始化也能正常用了,這就解決了迴圈依賴。
Spring 是如何 解決迴圈依賴的問題
初次遇到這個問題是在開發中,但是沒有深究,前一陣參加面試就被問到這個問題,當時真是非常後悔,怎麼沒有好好研究一下呢。現在來亡羊補牢吧。迴圈依賴的定義 迴圈依賴就是迴圈引用,就是兩個或多個bean 相互之間的持有對方,比如circlea 引用circleb circleb 引用circlec,circ...
Spring如何解決迴圈依賴
比如 在a類引入b物件,在b類引入a物件,建立a的時候需要依賴b,建立b的時候需要依賴a,而各自建立物件的時候,其互相依賴的物件還沒有建立完成,就導致各自都無法成功建立物件。這就是迴圈依賴。class aclass b解決迴圈依賴的方法很簡單,如下所示,先例項化a和b,此時都沒初始化,即都沒有對各自...
spring如何解決迴圈依賴
1.構造器注入 無法解決 構造器注入時,a,b都沒有進行初始化物件 構造方法無法執行完成 2.spring 為了解決單例的迴圈依賴問題,使用了 快取。其中一級快取為單例池 singletonobjects 二級快取為提前 物件 earlysingletonobjects 快取為提前 物件工廠 sin...