您好,登錄后才能下訂單哦!
循環(huán)依賴(lài)是指兩個(gè)或者多個(gè)Bean之前相互持有對(duì)方。在Spring中循環(huán)依賴(lài)一般有三種方式:
構(gòu)造函數(shù)循環(huán)依賴(lài)
setter方法循環(huán)依賴(lài)
prototype 范圍的依賴(lài)處理
在Spring中構(gòu)造函數(shù)循環(huán)依賴(lài)是無(wú)法解決的,因?yàn)闃?gòu)造函數(shù)依賴(lài)其實(shí)是方法間循環(huán)調(diào)用的一種,會(huì)發(fā)生死循環(huán)。但是在Spring中會(huì)直接拋出BeanCurrentlyInCreationException
異常。源碼如下:
//?在緩存中獲取Bean,如果沒(méi)有就創(chuàng)建Beanpublic?Object?getSingleton(String?beanName,?ObjectFactory<?>?singletonFactory)?{ Assert.notNull(beanName,?"'beanName'?must?not?be?null"); synchronized?(this.singletonObjects)?{ //?在緩存中獲取Bean Object?singletonObject?=?this.singletonObjects.get(beanName); if?(singletonObject?==?null)?{ //?判斷容器是否正在銷(xiāo)毀單實(shí)例Bean if?(this.singletonsCurrentlyInDestruction)?{ throw?new?BeanCreationNotAllowedException(beanName, "Singleton?bean?creation?not?allowed?while?singletons?of?this?factory?are?in?destruction?"?+ "(Do?not?request?a?bean?from?a?BeanFactory?in?a?destroy?method?implementation!)"); } //?將當(dāng)前需要?jiǎng)?chuàng)建的Bean標(biāo)示放到Set集合,如果失敗則拋出BeanCurrentlyInCreationException異常 beforeSingletonCreation(beanName); boolean?newSingleton?=?false; boolean?recordSuppressedExceptions?=?(this.suppressedExceptions?==?null); if?(recordSuppressedExceptions)?{ this.suppressedExceptions?=?new?LinkedHashSet<Exception>(); } try?{ //?創(chuàng)建Bean實(shí)例 singletonObject?=?singletonFactory.getObject(); newSingleton?=?true; } ... if?(newSingleton)?{ //?將Bean實(shí)例注冊(cè)到singletonObjects容器中 addSingleton(beanName,?singletonObject); } } return?(singletonObject?!=?NULL_OBJECT???singletonObject?:?null); } }protected?void?beforeSingletonCreation(String?beanName)?{ //?將當(dāng)前需要?jiǎng)?chuàng)建的Bean標(biāo)示方法Set集合,如果失敗則拋出BeanCurrentlyInCreationException異常 if?(!this.inCreationCheckExclusions.contains(beanName)?&&?!this.singletonsCurrentlyInCreation.add(beanName))?{ throw?new?BeanCurrentlyInCreationException(beanName); } }
執(zhí)行過(guò)程:
從緩存中獲取Bean,如果沒(méi)有則走創(chuàng)建Bean流程
判斷容器是否正在銷(xiāo)毀單實(shí)例Bean,如果是則不創(chuàng)建Bean
將當(dāng)前需要?jiǎng)?chuàng)建的Bean標(biāo)示(name)放入Set集合中(當(dāng)前正在創(chuàng)建的Bean池),如果放入失敗則拋出BeanCurrentlyInCreationException
異常
創(chuàng)建Bean實(shí)例
將Bean實(shí)例注冊(cè)到容器(放到緩存中)
解決構(gòu)造函數(shù)依賴(lài)主要是第3步實(shí)現(xiàn)的,Spring在容器創(chuàng)建的Bean的時(shí)候,會(huì)將Bean的標(biāo)示(name)放到一個(gè)Set集合里面(當(dāng)前正在創(chuàng)建的Bean池)。當(dāng)在創(chuàng)建Bean的過(guò)程中,發(fā)現(xiàn)自已經(jīng)在這個(gè)Set集合中時(shí),就直接會(huì)拋出
BeanCurrentlyInCreationException
異常,而不會(huì)發(fā)生死循環(huán)。
@Servicepublic?class?AService?{????@Autowired ????private?BService?bService;????@Autowired ????public?void?setbService(BService?bService)?{????????this.bService?=?bService; ????} }
這兩種方式都算是setter方法依賴(lài)。我們創(chuàng)建單實(shí)例Bean的大致過(guò)程可以劃分成三個(gè)階段:
實(shí)例化?createBeanInstance(beanName, mbd, args);
設(shè)置屬性值?populateBean(beanName, mbd, instanceWrapper);
初始化?initializeBean(beanName, exposedObject, mbd);
對(duì)于Setter注入造成的循環(huán)依賴(lài),Spring容器是在創(chuàng)建Bean第一步實(shí)例化后,就將Bean的引用提前暴露出來(lái)。通過(guò)提前暴露出一個(gè)單例工廠方法,從而使得其他Bean可以引用到該Bean。
創(chuàng)建Bean時(shí)提前暴露剛完成第一步的Bean,源碼如下:
addSingletonFactory(beanName,?new?ObjectFactory<Object>()?{ @Override public?Object?getObject()?throws?BeansException?{ return?getEarlyBeanReference(beanName,?mbd,?bean); } });//?將單例工廠放入緩存中protected?void?addSingletonFactory(String?beanName,?ObjectFactory<?>?singletonFactory)?{ Assert.notNull(singletonFactory,?"Singleton?factory?must?not?be?null"); synchronized?(this.singletonObjects)?{ if?(!this.singletonObjects.containsKey(beanName))?{ this.singletonFactories.put(beanName,?singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
自動(dòng)裝配過(guò)程中獲取單實(shí)例Bean,源碼如下:
protected?Object?getSingleton(String?beanName,?boolean?allowEarlyReference)?{ Object?singletonObject?=?this.singletonObjects.get(beanName); if?(singletonObject?==?null?&&?isSingletonCurrentlyInCreation(beanName))?{ synchronized?(this.singletonObjects)?{ singletonObject?=?this.earlySingletonObjects.get(beanName); if?(singletonObject?==?null?&&?allowEarlyReference)?{ ObjectFactory<?>?singletonFactory?=?this.singletonFactories.get(beanName); if?(singletonFactory?!=?null)?{ singletonObject?=?singletonFactory.getObject(); this.earlySingletonObjects.put(beanName,?singletonObject); this.singletonFactories.remove(beanName); } } } } return?(singletonObject?!=?NULL_OBJECT???singletonObject?:?null); }
我們可以看到,在自動(dòng)裝配Bean的過(guò)程中,會(huì)去找三個(gè)緩存:
singletonObjects:存放完成創(chuàng)建的Bean所有步驟的單實(shí)例Bean
earlySingletonObjects:存放只完成了創(chuàng)建Bean的第一步,且是由單實(shí)例工廠創(chuàng)建的Bean
singletonFactories:存放只完成了創(chuàng)建Bean的第一步后,提前暴露Bean的單實(shí)例工廠。http://www.chacha8.cn/detail/1132398214.html
這里為什么會(huì)用一個(gè)三級(jí)緩存呢,為啥不直接將只完成了創(chuàng)建Bean的第一步的Bean直接方到
earlySingletonObjects
緩存中呢?我們跟入
?getEarlyBeanReference(beanName, mbd, bean)
我們可以發(fā)現(xiàn),單實(shí)例工廠方法返回Bean的時(shí)候還執(zhí)行了后置處理器的,在后置處理器中我們還可以對(duì)Bean進(jìn)行一些特殊處理。如果我們直接將剛完成實(shí)例化的Bean放入earlySingletonObjects
緩存中,那么失去對(duì)Bean進(jìn)行特殊處理的機(jī)會(huì)。
源碼如下:
protected?Object?getEarlyBeanReference(String?beanName,?RootBeanDefinition?mbd,?Object?bean)?{ Object?exposedObject?=?bean; if?(bean?!=?null?&&?!mbd.isSynthetic()?&&?hasInstantiationAwareBeanPostProcessors())?{ for?(BeanPostProcessor?bp?:?getBeanPostProcessors())?{ if?(bp?instanceof?SmartInstantiationAwareBeanPostProcessor)?{ SmartInstantiationAwareBeanPostProcessor?ibp?=?(SmartInstantiationAwareBeanPostProcessor)?bp; exposedObject?=?ibp.getEarlyBeanReference(exposedObject,?beanName); if?(exposedObject?==?null)?{ return?null; } } } } return?exposedObject; }
對(duì)于
singleton?
作用域 bean ,可以通過(guò)setAllowCircularReferences(false);
來(lái)禁用循環(huán)引用。鄭州不育不孕醫(yī)院:http://www.zzchyy110.com/
對(duì)于prototype?
作用域 bean, Spring 容器無(wú)法完成依賴(lài)注入,因?yàn)?Spring 容器不進(jìn)行緩存prototype
作用域的 bean ,因此無(wú)法提前暴露一個(gè)創(chuàng)建中的 bean 示。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。