亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring 源碼(八)循環依賴

發布時間:2020-10-19 21:33:41 來源:網絡 閱讀:171 作者:艾弗森哇 欄目:開發技術

循環依賴是指兩個或者多個Bean之前相互持有對方。在Spring中循環依賴一般有三種方式:

  1. 構造函數循環依賴

  2. setter方法循環依賴

  3. prototype 范圍的依賴處理

構造函數循環依賴

在Spring中構造函數循環依賴是無法解決的,因為構造函數依賴其實是方法間循環調用的一種,會發生死循環。但是在Spring中會直接拋出BeanCurrentlyInCreationException異常。源碼如下:

//?在緩存中獲取Bean,如果沒有就創建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)?{			//?判斷容器是否正在銷毀單實例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!)");
			}			//?將當前需要創建的Bean標示放到Set集合,如果失敗則拋出BeanCurrentlyInCreationException異常
			beforeSingletonCreation(beanName);			boolean?newSingleton?=?false;			boolean?recordSuppressedExceptions?=?(this.suppressedExceptions?==?null);			if?(recordSuppressedExceptions)?{				this.suppressedExceptions?=?new?LinkedHashSet<Exception>();
			}			try?{				//?創建Bean實例
				singletonObject?=?singletonFactory.getObject();
				newSingleton?=?true;
			}
			...			if?(newSingleton)?{				//?將Bean實例注冊到singletonObjects容器中
				addSingleton(beanName,?singletonObject);
			}
		}		return?(singletonObject?!=?NULL_OBJECT???singletonObject?:?null);
	}
}protected?void?beforeSingletonCreation(String?beanName)?{	//?將當前需要創建的Bean標示方法Set集合,如果失敗則拋出BeanCurrentlyInCreationException異常
	if?(!this.inCreationCheckExclusions.contains(beanName)?&&?!this.singletonsCurrentlyInCreation.add(beanName))?{		throw?new?BeanCurrentlyInCreationException(beanName);
	}
}

執行過程:

  1. 從緩存中獲取Bean,如果沒有則走創建Bean流程

  2. 判斷容器是否正在銷毀單實例Bean,如果是則不創建Bean

  3. 將當前需要創建的Bean標示(name)放入Set集合中(當前正在創建的Bean池),如果放入失敗則拋出BeanCurrentlyInCreationException異常

  4. 創建Bean實例

  5. 將Bean實例注冊到容器(放到緩存中)

解決構造函數依賴主要是第3步實現的,Spring在容器創建的Bean的時候,會將Bean的標示(name)放到一個Set集合里面(當前正在創建的Bean池)。當在創建Bean的過程中,發現自已經在這個Set集合中時,就直接會拋出BeanCurrentlyInCreationException異常,而不會發生死循環。

setter方法循環依賴

@Servicepublic?class?AService?{????@Autowired
????private?BService?bService;????@Autowired
????public?void?setbService(BService?bService)?{????????this.bService?=?bService;
????}
}

這兩種方式都算是setter方法依賴。我們創建單實例Bean的大致過程可以劃分成三個階段:

  1. 實例化?createBeanInstance(beanName, mbd, args);

  2. 設置屬性值?populateBean(beanName, mbd, instanceWrapper);

  3. 初始化?initializeBean(beanName, exposedObject, mbd);

對于Setter注入造成的循環依賴,Spring容器是在創建Bean第一步實例化后,就將Bean的引用提前暴露出來。通過提前暴露出一個單例工廠方法,從而使得其他Bean可以引用到該Bean。

創建Bean時提前暴露剛完成第一步的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);
		}
	}
}

自動裝配過程中獲取單實例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);
}

我們可以看到,在自動裝配Bean的過程中,會去找三個緩存:

  1. singletonObjects:存放完成創建的Bean所有步驟的單實例Bean

  2. earlySingletonObjects:存放只完成了創建Bean的第一步,且是由單實例工廠創建的Bean

  3. singletonFactories:存放只完成了創建Bean的第一步后,提前暴露Bean的單實例工廠。http://www.chacha8.cn/detail/1132398214.html

這里為什么會用一個三級緩存呢,為啥不直接將只完成了創建Bean的第一步的Bean直接方到earlySingletonObjects緩存中呢?

我們跟入?getEarlyBeanReference(beanName, mbd, bean)我們可以發現,單實例工廠方法返回Bean的時候還執行了后置處理器的,在后置處理器中我們還可以對Bean進行一些特殊處理。如果我們直接將剛完成實例化的Bean放入earlySingletonObjects緩存中,那么失去對Bean進行特殊處理的機會。

源碼如下:

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;
}

對于singleton?作用域 bean ,可以通過setAllowCircularReferences(false);來禁用循環引用。鄭州不育不孕醫院:http://www.zzchyy110.com/

prototype 范圍的依賴處理

對于prototype?作用域 bean, Spring 容器無法完成依賴注入,因為 Spring 容器不進行緩存prototype作用域的 bean ,因此無法提前暴露一個創建中的 bean 示。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

上栗县| 通山县| 三门县| 金山区| 社旗县| 永胜县| 鹤庆县| 岗巴县| 呼伦贝尔市| 中超| 南开区| 蓬莱市| 潜江市| 邵阳市| 龙山县| 延吉市| 湘阴县| 长岭县| 横山县| 麻江县| 正镶白旗| 西青区| 曲靖市| 东城区| 蕉岭县| 乐山市| 德令哈市| 龙泉市| 吴江市| 沿河| 自治县| 嘉义县| 秀山| 武清区| 景宁| 长乐市| 建平县| 观塘区| 南投县| 广水市| 珲春市|