循環(huán)依賴
創(chuàng)新互聯(lián)專注于冊(cè)亨企業(yè)網(wǎng)站建設(shè),自適應(yīng)網(wǎng)站建設(shè),商城網(wǎng)站制作。冊(cè)亨網(wǎng)站建設(shè)公司,為冊(cè)亨等地區(qū)提供建站服務(wù)。全流程按需設(shè)計(jì)網(wǎng)站,專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
所謂循環(huán)依賴就是多個(gè)Bean之間依賴關(guān)系形成一個(gè)閉環(huán),例如A->B->C->...->A 這種情況,當(dāng)然,最簡(jiǎn)單的循環(huán)依賴就是2個(gè)Bean之間互相依賴:A->B(A依賴B), B->A(B依賴A) 。在Spring中,如果A->B,那么在創(chuàng)建A的過程中會(huì)去創(chuàng)建B,在創(chuàng)建B(或B的依賴)的過程中又發(fā)現(xiàn)B->A,這個(gè)時(shí)候就出現(xiàn)了循環(huán)依賴的現(xiàn)象。
循環(huán)依賴的解決
spring中的循環(huán)依賴只有當(dāng)
1.Bean是單例,
2.通過屬性注入的情況
這兩個(gè)條件滿足的情況下是沒問題的。但是如果是通過構(gòu)造器依賴,或者不是單例模式的情況下循環(huán)依賴就會(huì)拋出異常BeanCurrentlyInCreationException。下面從代碼層面上解析一下為什么。
Prototype的循環(huán)依賴問題
為什么最先介紹Prototype的循環(huán)依賴呢,因?yàn)榭梢皂槺憬榻B在Spring中創(chuàng)建Bean的流程核心流程:在AbstractFoctory的doGetBean的方法。這個(gè)方法很長(zhǎng),這里只寫出核心邏輯,并在注解上注明了個(gè)人理解:
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
//嘗試獲取單例對(duì)象,因?yàn)閟pring大部分的bean都是單例的,所以這里先嘗試能否獲取。
registered singletons.
Object sharedInstance = getSingleton(beanName);
//單例存在的情況下,那么beanName返回的肯定是單例類,但是這里還需要判斷是不是FactoryBean
if (sharedInstance != null && args == null) {
...
//FactoryBean應(yīng)該返回getObject()對(duì)象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//走到這里,有可能beanName是單例模式,但之前并沒有實(shí)例化,或者是Prototype類型。
//首先判斷不是循環(huán)依賴,這里的循環(huán)依賴指的是Prototype類型
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 如果是單例,則創(chuàng)建單例模式
if (mbd.isSingleton()) {
// !!!這里是解決單例循環(huán)依賴的關(guān)鍵,后面再分析
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// 原型模式,則創(chuàng)建一個(gè)新對(duì)象.
Object prototypeInstance = null;
try {
/*這里是Prototype循環(huán)依賴的問題,會(huì)記錄在map中beanName,
如果在解決當(dāng)前Bean的依賴過程中還依賴當(dāng)前Bean,
則說明了出現(xiàn)了循環(huán)依賴
*/
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
//對(duì)應(yīng)beforePrototypeCreation(),從map中移除
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
...
}
}
...
return (T) bean;
}
可以看出,該流程中就考慮了Prototype的循環(huán)依賴的問題,只要在創(chuàng)建Prototype的Bean中出現(xiàn)循環(huán)依賴那么就拋出異常。但是在singleton的情況下,則通過另外的方式來解決。
Singleton的循環(huán)依賴之構(gòu)造注入
在上面介紹中,出現(xiàn)了一個(gè)很關(guān)鍵的地方:
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
throw ex;
}
}
});
這個(gè)getSingleton涉及到了ObjectFactory這個(gè)接口類,這個(gè)接口的功能和FactoryBean類似,但是主要是用來解決循環(huán)依賴的。在初始化過程同決定返回的Singleton對(duì)象是。關(guān)于單例的對(duì)象的創(chuàng)建,又要介紹一下DefaultSingletonBeanRegistry這個(gè)類,這個(gè)類主要用來幫助創(chuàng)建單例模式,其中主要的屬性:
/** 緩存創(chuàng)建的單例對(duì)象: bean名字 --> bean對(duì)象 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** 緩存單例的factory,就是ObjectFactory這個(gè)東西,: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** 也是緩存創(chuàng)建的單例對(duì)象,功能和singletonObjects不一樣,
在bean構(gòu)造成功之后,屬性初始化之前會(huì)把對(duì)象放入到這里,
主要是用于解決屬性注入的循環(huán)引用: bean name --> bean instance
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
/** 記錄在創(chuàng)建單例對(duì)象中循環(huán)依賴的問題,還記得Prototype中又記錄創(chuàng)建過程中依賴的map嗎?
在Prototype中只要出現(xiàn)了循環(huán)依賴就拋出異常,而在單例中會(huì)嘗試解決 */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));
現(xiàn)在回過來看getSingleton(beanName, new ObjectFactory<Object>()這個(gè)方法的實(shí)現(xiàn)。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
//嘗試在singletonObjects中獲取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//不存在則創(chuàng)建
//把當(dāng)前beanName加入到singletonsCurrentlyInCreation中
beforeSingletonCreation(beanName);
try {
singletonObject = singletonFactory.getObject();
}
...
finally {
...
//從singletonsCurrentlyInCreation中刪除beanName
afterSingletonCreation(beanName);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
這段邏輯是不是和Prototype中解決循環(huán)類似,這里其實(shí)就是調(diào)用了ObjectFactory的getObject()獲取對(duì)象,回過頭去看前面代碼,ObjectFactory的getObject()方法實(shí)際調(diào)用的是createBean(beanName, mbd, args)。說到createBean(beanName, mbd, args)又不得不說AbstractAutowireCapableBeanFactory這個(gè)類,主要功能就是完成依賴注入的Bean的創(chuàng)建,這個(gè)類的createBean方法代碼如下,注意注解說明:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
...
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// 實(shí)例化bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//如果沒實(shí)例化則創(chuàng)建新的BeanWrapper
//如果是通過構(gòu)造器注入,這里是一個(gè)關(guān)鍵點(diǎn)
/*
因?yàn)樵贏初始化的時(shí)候發(fā)現(xiàn)構(gòu)造函數(shù)依賴B,就會(huì)去實(shí)例化B,
然后B也會(huì)運(yùn)行到這段邏輯,構(gòu)造函數(shù)中發(fā)現(xiàn)依賴A,
這個(gè)時(shí)候就會(huì)拋出循環(huán)依賴的異常
*/
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//如果當(dāng)前是單例,并且allowCircularReferences為true(默認(rèn)就是true,除非我們不希望Spring幫我們解決)
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
/*
!!!這里很重要,把構(gòu)造成功,但屬性還沒注入的
的bean加到singletonFactory中,這樣再解決A的依賴
過程中如果依賴A,就把這個(gè)半成品返回回去。
*/
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
Object exposedObject = bean;
try {
//自動(dòng)注入屬性
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
...
return exposedObject;
}
注解已經(jīng)注明了我的理解。就不再贅述
總結(jié)
上面代碼是我一邊debug一個(gè)寫下的,現(xiàn)在寫完了,根據(jù)自己的理解總結(jié)一下。
相關(guān)類說明

AbstractBeanFactory,這個(gè)類中包含了Bean創(chuàng)建的主要流程,在doGetBean這個(gè)方法中包含了對(duì)Prototype循環(huán)依賴處理。邏輯很簡(jiǎn)單,出現(xiàn)了循環(huán)依賴則直接拋出異常
DefaultSingletonBeanRegister 用于管理Singleton的對(duì)象的創(chuàng)建,以及解決循環(huán)依賴的問題,其中解決循環(huán)依賴的關(guān)鍵屬性就是了earlySingletonObjects,他會(huì)在構(gòu)造Singleton對(duì)象過程中暫時(shí)緩存構(gòu)造成功,但屬性還未注入的對(duì)象,這樣就可以解決循環(huán)依賴的問題。
AbstractAutowireCapableBeanFactory,自動(dòng)注入的相關(guān)邏輯,包自動(dòng)注入的對(duì)象的創(chuàng)建、初始化和注入。但如果在調(diào)用構(gòu)造函數(shù)中發(fā)現(xiàn)了循環(huán)依賴,則拋出異常
ObjectFactory,這個(gè)接口功能和FactoryBean類似,但是為了解決循環(huán)依賴,他決定了在獲取的getSingleton()是一個(gè)完成品還是一個(gè)半成品。
思考
如果A--構(gòu)造依賴->B,B--屬性依賴-->A,例如:
@Component
public class BeanA {
private BeanB beanB;
@Autowired
public BeanA(BeanB beanB) {
this.beanB = beanB;
}
}
@Component
public class BeanB {
@Autowired
private BeanA beanA;
}
這種情況會(huì)異常嗎?提示:都有可能
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
新聞名稱:spring循環(huán)依賴策略解析
當(dāng)前鏈接:http://chinadenli.net/article14/gejgde.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營銷推廣、品牌網(wǎng)站設(shè)計(jì)、標(biāo)簽優(yōu)化、網(wǎng)站排名、手機(jī)網(wǎng)站建設(shè)、用戶體驗(yàn)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)