循環(huán)依賴
1主穗、循環(huán)依賴的介紹
循環(huán)依賴想许,bean之間相互持有各自的引用,最終形成閉環(huán)屁柏。比如
bean的實(shí)例化有如下三個(gè)步驟:
1、createBeanInstance 搜锰,生成原始對(duì)象
2维贺、popoulateBean告唆,進(jìn)行屬性注入
3域携、instantiateBean ,進(jìn)行init-method初始化和后置處理
由此鱼喉,當(dāng)生成A對(duì)象之后秀鞭,此時(shí)還未進(jìn)行屬性注入,檢測(cè)到A有B屬性扛禽,調(diào)用getBean(B b)獲取B锋边,
開始進(jìn)行B的實(shí)例化,B生成對(duì)象之后编曼,進(jìn)行屬性注入豆巨,檢測(cè)到B有A屬性,這個(gè)時(shí)候掐场,就產(chǎn)生了循環(huán)依賴往扔。
循環(huán)依賴會(huì)出現(xiàn)在下面幾種情況:
1)構(gòu)造函數(shù)的循環(huán)依賴
2)屬性的循環(huán)依賴,分為單例和原型兩種情況來分析
2熊户、循環(huán)依賴的處理方式
2.1萍膛、單例的循環(huán)依賴
spring處理循環(huán)依賴是這樣的:使用三級(jí)緩存。
/** Cache of singleton objects: bean name --> bean instance */
/** 緩存單例bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
/** 緩存單例bean的構(gòu)造工廠 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance */
/** 緩存提前曝光的單例bean 即還未完成完整實(shí)例化的bean */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
這三級(jí)緩存分別是:
singletonObjects:?jiǎn)卫龑?duì)象工廠的cache嚷堡,這里存儲(chǔ)的是完整實(shí)例化之后的bean
singletonFactories:?jiǎn)卫龑?duì)象的ObjectFactory蝗罗,該ObjectFactory返回的對(duì)象就是還未進(jìn)行popoulateBean的原始對(duì)象
earlySingletonObjects:提前曝光的單例bean,就是已經(jīng)本身還未進(jìn)行屬性注入的bean蝌戒,已經(jīng)作為其他的bean的屬性注入到該bean中了串塑,比如A還未進(jìn)行屬性注入,但是被B引用到了北苟,注入到B中桩匪,此時(shí)就將A放到提前曝光的單例bean緩存earlySingletonObjects中。
針對(duì)單例進(jìn)行源碼分析:
假設(shè)A->B,B->A,以上bean對(duì)象存在循環(huán)依賴:
調(diào)用getBean(A)->AbstractBeanFactory.doGetBean(省略相關(guān)代碼粹淋,留下關(guān)鍵代碼)
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//針對(duì)beanName進(jìn)行處理
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//獲取緩存的單例bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
//獲取的bean當(dāng)前處于創(chuàng)建狀態(tài)吸祟,即還未初始化完成,僅僅是new出來而已桃移,屬性還沒注入完成屋匕,且存在依賴循環(huán)
//比如A->B,B->A
//1借杰、getBean(A),獲取到A的實(shí)例过吻,此時(shí)還未進(jìn)行注入
//2、開始注入,發(fā)現(xiàn)B屬性纤虽,開始getBean(B)乳绕,獲取到B的實(shí)例
//3、開始對(duì)B注入逼纸,發(fā)現(xiàn)A屬性洋措,獲取到還未注入完成的A,即處于isSingletonCurrentlyInCreation的A
//4杰刽、完成B的注入菠发,getBean(B)完成,然后A的注入也完成贺嫂,也就是在構(gòu)建單例的時(shí)候滓鸠,會(huì)將還未完成注入的A提前暴露,便于B完成注入
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//當(dāng)用戶輸入的beanname前綴為“&”第喳,要求獲取的是factoryBean
//否則獲取的就是普通的bean
//這里就是對(duì)這兩種情況進(jìn)行處理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Create bean instance.
//單例的處理
//首先創(chuàng)建beanFactory,即ObjectBeanFacotry并實(shí)現(xiàn)getObject接口
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
return (T) bean;
}
由于A是第一次初始化糜俗,故會(huì)調(diào)用getSingleton方法:
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
這里調(diào)用的是DefaultSingletonBeanRegistry.getSingleton
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
//鎖定singletonObjects,確保線程安全
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//對(duì)于正在創(chuàng)建狀態(tài)的單例bean曲饱,再次進(jìn)入此方法悠抹,拋出異常
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!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//進(jìn)行創(chuàng)建狀態(tài)的記錄 this.singletonsCurrentlyInCreation.add(beanName)
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//進(jìn)行創(chuàng)建狀態(tài)的移除 this.singletonsCurrentlyInCreation.remove(beanName)
afterSingletonCreation(beanName);
}
if (newSingleton) {
//將bean加載到對(duì)應(yīng)的容器中,并對(duì)相關(guān)輔助容器進(jìn)行bean的刪除
//this.singletonObjects.put(beanName, singletonObject);
//this.singletonFactories.remove(beanName);
//this.earlySingletonObjects.remove(beanName);
//this.registeredSingletons.add(beanName);
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
這個(gè)方法一共做了這么幾件事:
1扩淀、在創(chuàng)建實(shí)例之前锌钮,記錄正在創(chuàng)建狀態(tài),singletonsCurrentlyInCreation.add(beanName)
2引矩、創(chuàng)建實(shí)例梁丘,調(diào)用singletonFactory.getObject();
3、移除正在創(chuàng)建狀態(tài)旺韭,this.singletonsCurrentlyInCreation.remove(beanName)
4氛谜、將該bean緩存到單例緩存容器, this.singletonObjects.put(beanName, singletonObject);并且從相關(guān)的輔助容器刪除区端,如singletonFactories和earlySingletonObjects
進(jìn)入到singletonFactory.getObject();,這里調(diào)用的是AbstractAutowireCapableBeanFactory.doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//如果當(dāng)前是單例值漫,且允許循環(huán)依賴而且當(dāng)前bean處于創(chuàng)建狀態(tài)
//this.singletonFactories.put(beanName, singletonFactory);三級(jí)緩存添加實(shí)例對(duì)象工廠
//this.earlySingletonObjects.remove(beanName);二級(jí)緩存刪除實(shí)例對(duì)象
//this.registeredSingletons.add(beanName);
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
這個(gè)方法一共做了這么幾件事:
1、實(shí)例化bean
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
2织盼、如果當(dāng)前允許循環(huán)依賴且當(dāng)前bean是單例而且處于創(chuàng)建狀態(tài)杨何,將此單例的ObjectFactory加入到singletonFactories,且此factory返回的bean對(duì)象就是當(dāng)前實(shí)例化好的bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
3沥邻、進(jìn)行屬性注入populateBean(beanName, mbd, instanceWrapper);
4危虱、instantiateBean ,進(jìn)行init-method初始化和后置處理
從這里可以看出來唐全,在pupulateBean之前埃跷,singletonFactories存儲(chǔ)了該bean的factory蕊玷,然后進(jìn)行pupulateBean,發(fā)現(xiàn)B是A的屬性弥雹,然后調(diào)用getBean(B)對(duì)B進(jìn)行實(shí)例化垃帅,重復(fù)上面的步驟到B的屬性注入環(huán)節(jié),發(fā)現(xiàn)A是B的屬性剪勿,這個(gè)時(shí)候贸诚,再次調(diào)用getBean(A),此時(shí)緩存中已經(jīng)有了A了
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//針對(duì)beanName進(jìn)行處理
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//獲取緩存的單例bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
//獲取的bean當(dāng)前處于創(chuàng)建狀態(tài),即還未初始化完成厕吉,僅僅是new出來而已赦颇,屬性還沒注入完成,且存在依賴循環(huán)
//比如A->B赴涵,B->A
//1、getBean(A),獲取到A的實(shí)例订讼,此時(shí)還未進(jìn)行注入
//2髓窜、開始注入,發(fā)現(xiàn)B屬性欺殿,開始getBean(B)寄纵,獲取到B的實(shí)例
//3、開始對(duì)B注入脖苏,發(fā)現(xiàn)A屬性程拭,獲取到還未注入完成的A,即處于isSingletonCurrentlyInCreation的A
//4棍潘、完成B的注入恃鞋,getBean(B)完成,然后A的注入也完成亦歉,也就是在構(gòu)建單例的時(shí)候恤浪,會(huì)將還未完成注入的A提前暴露,便于B完成注入
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//當(dāng)用戶輸入的beanname前綴為“&”肴楷,要求獲取的是factoryBean
//否則獲取的就是普通的bean
//這里就是對(duì)這兩種情況進(jìn)行處理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
return (T)bean;
}
重點(diǎn)關(guān)注
//獲取緩存的單例bean
Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
/** 從singletonObjects獲取bean實(shí)例 */
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
/** 如果singletonObjects還沒有此bean水由,有兩種情況
* 1、說明還未完全實(shí)例化赛蔫,正在創(chuàng)建狀態(tài)砂客,先從earlySingletonObjects獲取
* 2、該bean還沒開始創(chuàng)建
*/
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
/** 如果earlySingletonObjects還沒有此bean呵恢,有兩種情況
* 1鞠值、說明還未曝光,即被其他bean注入渗钉,正在創(chuàng)建狀態(tài)齿诉,先從singletonFactories獲取
* 2、該bean還沒開始創(chuàng)建*/
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
/** factory不為空,說明處于正在創(chuàng)建狀態(tài)粤剧,且還未被其他bean注入歇竟,從singletonObject取出bean
* 1、將此bean放到提前曝光的緩存earlySingletonObjects中
* 2抵恋、同時(shí)刪除在singletonFactories的緩存
* */
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
這個(gè)方法做了這么一件事焕议,逐步從三級(jí)緩存中獲取bean:
1)先到singletonObjects獲取,如果有表示實(shí)例化已經(jīng)完成弧关;
2)否則到earlySingletonObjects獲取盅安,如果有表示已經(jīng)有bean,且存在循環(huán)依賴世囊,將此bean作為屬性注入了
3)否則到singletonFactories獲取别瞭,如果存在循環(huán)依賴,且此屬性是第一次被其他bean作為屬性注入
這里B將A第一次作為屬性注入株憾,返回的是singletonFactories生成的bean蝙寨,也就是剛剛未完成實(shí)例化的A對(duì)象。
此時(shí)A的引用從singletonFactories轉(zhuǎn)移到earlySingletonObjects嗤瞎,表示已經(jīng)被曝光了墙歪。
此時(shí)B已經(jīng)完成屬性注入,到這里贝奇,其實(shí)B已經(jīng)完成了實(shí)例化虹菲,也可以說A完成了屬性注入了。
接下來回顧獲取A的這個(gè)方法DefaultSingletonBeanRegistry.getSingleton掉瞳,其實(shí)到了這里毕源,我們也只是完成了singletonFactory.getObject(),最后一步陕习,將A放在singletonObjects中:
//將bean加載到對(duì)應(yīng)的容器中脑豹,并對(duì)相關(guān)輔助容器進(jìn)行bean的刪除
//this.singletonObjects.put(beanName, singletonObject);
//this.singletonFactories.remove(beanName);
//this.earlySingletonObjects.remove(beanName);
//this.registeredSingletons.add(beanName);
addSingleton(beanName, singletonObject);
至此,單例的循環(huán)依賴得到了解決衡查。
其實(shí)瘩欺,解決循環(huán)依賴就在于未完成實(shí)例化的Bean在三級(jí)緩存中的轉(zhuǎn)移:
1)A剛實(shí)例化,未進(jìn)行屬性注入拌牲,添加到singletonFactories
2)正在屬性注入B俱饿,且同時(shí)第一次被B所依賴,B在屬性注入的時(shí)候?qū)由singletonFactories轉(zhuǎn)移至earlySingletonObjects
3)待B屬性注入完成塌忽,完成實(shí)例化拍埠,A也就完成了實(shí)例化,此時(shí)土居,將A轉(zhuǎn)移至singletonObjects
同理枣购,B亦是如此
2.2嬉探、構(gòu)造方法的循環(huán)依賴
由于此循環(huán)依賴是在對(duì)象實(shí)例化的時(shí)候進(jìn)行的,也就是說這種依賴是無法像單例一樣生成對(duì)象棉圈,那么這種循環(huán)依賴也只能通過拋出異常處理
2.3涩堤、原型模式的循環(huán)依賴
由于原型模式不像單例一樣會(huì)提供緩存來進(jìn)行輔助存儲(chǔ)未完整實(shí)例化的bean,故spring的處理也是直接拋出異常
//對(duì)于原型模式的循環(huán)依賴分瘾,直接拋出異常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}