上一節分析了Spring如何讀取xml配置文件並最終將配置的POJO類生成一個個BeanDefinition
註冊到IOC容器的過程,主要是針對直接配置在xml中的標籤來分析的,應該來講生成BeanDefinition指數讀取配置放入到指定屬性中,並非太難理解。 IOC的第二步是經過getBean()
獲取一個bean實例,相對而言,建立一個bean比生成一個BeanDefinition
熱鬧多了,bean的singleton和prototype模式,bean的屬性注入,bean的循環依賴,bean方法攔截等等都是建立一個bean要解決的問題,而這一些對於使用者來講無需關注,但若是能瞭解Spring的實現原理,遇到問題纔不會手忙腳亂。java
BeanFactory
是Spring提供給咱們用於獲取bean實例的接口,這個接口很簡單,沒有多餘的方法,只有一個很是核心的getBean(),經過該方法就能夠獲取一個bean的實例。在Spring中該接口是由DefaultListableBeanFactory
實現,真正的業務處理在AbstractBeanFactory
類裏面,再來回憶下這張類圖:算法
getBean
的入口在DefaultListableBeanFactory
,準確來講是在AbstractBeanFactory
這個類裏面,由於getBean()的不少實現都是在AbstractBeanFactory
這個抽象類裏面。spring
再來看一下測試案例:數組
@Test
public void testSpringLoad() {
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("spring/spring-context.xml");
Person person= (Person) application.getBean("person");
BeanService beanService= (BeanService) application.getBean("beanService");
System.out.println(beanService);
System.out.println(person);
}
複製代碼
在這個測試案例裏,須要經過application獲取到一個person和beanService的實例,這個實例在xml的配置信息以下:緩存
<!--setter注入-->
<bean id="beanService" class="com.yms.manager.model.BeanService">
<property name="mapper" ref="userDao"/>
<property name="name" value="lijinpeng"/>
<property name="sex" value="false"/>
</bean>
<!--構造器注入-->
<bean id="person" class="com.yms.manager.model.Person">
<constructor-arg name="age" value="26"/>
<constructor-arg name="name" value="dangwendi"/>
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="sex" value="true"/>
</bean>
<bean id="userDao" class="com.yms.manager.model.UserDao"/>
複製代碼
經過這些配置,須要獲得預期的結果:安全
這兩種方式實際上對應了setter注入和構造器注入,因爲getBean()裏面的實現很是複雜,針對註解和aop使用了幾個BeanPostProcessor
在bean的不一樣生命週期執行注入,裏面用的類不少,若是把全部的狀況都分析下來,估計很快就懵了,因此仍是經過這個簡單的案例來分析一下Spring是如何實例化bean的,在分析原理時相對而言容易理解一點。app
BeanFactory裏面經過getBean獲取bean實例,先來看一下getBean的幾個重載:ide
getBean(String name)
函數
getBean(Class<T> requiredType)
post
getBean(String name, Class<T> requiredType)
getBean(String name, Object... args)
這四個重載方法都用於獲取bean實例,經過參數名就能夠看出,name就是bean實例化時候的beanId,這個id的值若是經過xml配置就是bean的name屬性,若是是註解就是自動生成的,默認是類名的首字母小寫。requiredType是須要獲取指定Class的bean,這裏重點了解一下最後一個重載,這個方法第二個參數是一個動態數組,這個動態數組主要用於指定建立bean實例時候要使用的構造函數的參數列表或者建立bean的工廠方法返回bean的方法參數列表,這也就意味着,咱們能夠在使用的bean的時候能夠經過指定不通的構造參數獲取bean的不一樣對象,經常使用於工廠模式。
在看源碼之前,首先來想一下若是本身簡單實現,應該如何獲取一個bean,前面說過IOC實際上就是一個線程安全的hashMap,準確來講是 ConcurrentHashMap<String, Object>
,知道這個那就簡單了,因此大概應該是這個步驟:
經過beanName去第一步生成的BeanDefinitions查找BeanDefinition
從BeanDefinition
獲取className,匹配一個合適的構造函數,經過反射獲取一個實例對象
從BeanDefinition
獲取配置的屬性值,經過反射注入到實例對象中
返回bean實例
上面的分析步驟是針對getBean(String name) 這個重載方法的,若是是getBean(Class<T> requiredType)
則在第二步須要變更一下:
BeanDefinition
提供一個方法resolveBeanClass
將配置className解析成beanClass對象,而後從BeanDefinitions查找beanClass爲requiredType的對象返回實例。而後進行三、4步驟便可。
Spring的實現方式實際上覆雜得多,簡單來講Spring是這麼處理得:
先從緩存中查找是否已經存在解析過的名爲name,若是有,直接返回
若是bean是FactoryBean
或者是bean工廠類,調用getObject()或者工廠方法獲取bean實例
匹配合適的構造函數,經過反射建立一個bean的實例
經過ObjectFactory
提早暴露bean,解決循環依賴的問題
調用populateBean
方法完成bean的屬性注入
將實例化完成的bean放入到IOC容器中
spring中bean的獲取,針對註解注入和AOP的入口都是在實現了BeanPostProcessor
的類裏實現的,這些類共同組成了bean實例化過程當中的一部分生命週期,經過上面對getBean的簡要分析,接下來就去看看Spring的源碼部分吧。
上面說過,AbstractBeanFactory
是建立bean實例的程序入口,具體到方法是doGetBean
,因爲這個方法比較長,這裏只分析比較重要的邏輯,下面的方法比源碼有些精簡,不過核心業務都是有的:
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly){
//解析bean的真正name,若是bean是工廠類,name前綴會加&,須要去掉
final String beanName = transformedBeanName(name);
//核心1:從單例容器中獲取緩存的bean
Object sharedInstance = getSingleton(beanName);
//若是從單例容器中到緩存的bean並且構造函數參數列表爲空
if (sharedInstance != null && args == null)
{
//核心2:直接獲取實例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else{
//驗證當前bean實例是否正在建立中,若是是 直接拋出異常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//中間省略了經過工廠方式建立bean的代碼
.............
if (!typeCheckOnly)
{
//核心3:將當前bean實例放入alreadyCreated集合裏,標識這個bean準備建立了
markBeanAsCreated(beanName);
}
try{
//從BeanDefinitions中獲取該實例的BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//檢查要建立的實例bean的修飾符,是否容許被實例化
checkMergedBeanDefinition(mbd, beanName, args);
//省略了實例化bean的全部依賴bean的過程,建立過程是同樣的
.............
// Create bean instance.
if (mbd.isSingleton()) {
//核心4:建立單例bean
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
//爲了解決循環依賴,spring將使用ObjectFactory表示bean,提早暴露bean
//當真正屬性注入的時候,調用ObjectFactory的getObject()方法獲取bean實例
@Override
public Object getObject() throws BeansException {
try {
//核心5:真正建立bean的方法,重點要看的方法
return createBean(beanName, mbd, args);
}catch (BeansException ex) {
//若是建立bean異常 作一些清除工做
//包括將bean從alreadyCreated,singletonsCurrentlyInCreation等容器中清除
destroySingleton(beanName);
throw ex;
}}});
//獲取真正的bean,因爲bean能夠經過FactortBean或者工廠bean的方式建立
//因此這個方法用於從Factorybean或者工廠bean獲取要建立的真正的bean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
//省略 原型模式的建立
.............
}else
{
//省略scope做用於的建立
.............
}
}catch(BeansException ex){
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
//若是requiredType不爲空,嘗試將獲取的bean轉換成requiredType
.............
}
}
複製代碼
spring源碼裏面這段代碼其實特別長,若是都搬下來,恐怕邏輯並不會這麼清晰,這裏主要分析主上上的核心方法,這些方法裏面涵括了實例化一個bean的全部操做。
首先分析這個方法的幾個參數:
name:顧名思義就是bean的name
requiredType:bean對象的類型
args:建立bean實例構造函數所須要的參數列表,對應getBean
第四個重載方法
typeCheckOnly:bean實例是否包含一個類型檢查
從當前案例來看,咱們只使用了name屬性,剩下的三個參數都是默認值,其中requiredType和args都是null,typeCheckOnly是false。從上面分析來看,實例化一個bean首先要獲取構造函數進行初始化,而後設置屬性值,咱們來看這樣一個狀況,若是A中有一個屬性爲B b,B中也有一個屬性A a,當實例化bean設置屬性的屬性,A會查找B的實例注入給屬性b,若是B不存在會去建立B實例,當B實例設置屬性a的時候回去查找A的實例,若是不存在則會建立A的實例,這個時候就會致使循環依賴的問題,Spring解決循環依賴是經過ObjectFactory
做爲中間對象提早暴露實例解決的。而且將這些提早暴露的實例放入到earlySingletonObjects中,當須要真正使用bean實例時,就會調用ObjectFactory
的getObject
獲取,固然Spring只是經過這種方式解決了單例模式下的循環依賴問題,瞭解了這點下面看getBean也許會容易點。
梳理一下這個方法所幹的事情:
獲取真正的beanName,說白了就是將FactoryBean
或者bean工廠類前面的&去掉
從單例容器中查找bean的緩存
若是緩存中存在,並且bean構造函數沒有任何參數,直接建立bean實例返回
若是緩存不存在,將當前bean標記爲建立狀態,開始建立bean實例
從BeanDefinitions中查找bean聲明,經過BeanDefinition建立bean返回
若是requiredType不爲空,還須要將上面步驟生成的bean轉換成requiredType返回
接下里就看看各個方法所做的事情吧,首先看getSingleton(beanName)
,直接定位到關鍵的方法實現:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//從單例的IOC也就是hashMap中獲取是否已經存在bean實例
Object singletonObject = this.singletonObjects.get(beanName);
//若是緩存不存在&&當前正常建立的單例對象就是該bean實例就進入建立方法
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//爲了線程安全將單例的IOC容器鎖起來
synchronized (this.singletonObjects) {
//從提早暴露容器中查找是否存在對應的ObjectFactory
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//若是仍是找不到就從bean工廠類的緩存中查找
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//若是存在建立該實例的bean的工廠類 則經過工廠類建立bean
singletonObject = singletonFactory.getObject();
//將建立的bean放入到提早暴露容器集合裏
this.earlySingletonObjects.put(beanName, singletonObject);
//由於已經存在了實例無需再經過工廠建立,
//將建立該實例的工廠從工廠讓其中刪除
this.singletonFactories.remove(beanName);
}
}
}
}
//返回從緩存中獲取結果
return (singletonObject != hNULL_OBJECT ? singletonObject : null);
}
複製代碼
這個方法的目的就是從單例緩存中獲取bean的實例,首先從單例容器中獲取,若是獲取不到,再到提早暴露的容器裏去查找,這個容器是earlySingletonObjects
,也是一個ConcurrentHashMap,這個容器存在的意義就是爲了解決循環依賴,因此將bean轉換成ObjectFactory
提早放入到容器中暴露出去,若是這個還找不到,就去建立bean的工廠類裏面去查找,什麼是bean的工廠類呢,看下這段配置就明瞭了:
<bean id="bankPayService" class="com.yms.manager.serviceImpl.BankPayServiceImplFactory" factory-method="getService"/>
複製代碼
bean的獲取是經過BankPayServiceImplFactory
的getService
方法獲取的,BankPayServiceImplFactory
就叫作bean的工廠類,毫無疑問,若是是第一次使用bean實例,經過這個方法什麼也獲取不到,最終返回一個null,當在第二次使用bean實例的時候,直接執行到這裏其實能夠獲取到第一次加載的bean的,對單例做用域的bean來講,無需再次實例化bean,極大的提升了spring的性能,這也是這一步爲什麼如此關鍵的緣由。
上面說了,若是是第一次獲取某個bean實例,不管如何也沒法從緩存中獲取到bean的實例,但鑑於代碼執行順序緣由,仍是先把獲取緩存的bean的狀況分析下去,假如spring經過緩存拿到了bean實例對象,並不會直接返回對象,還須要執行方法 getObjectForBeanInstance
:
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 若是bean實例不是FactoryBean 但name又是工廠的前綴引用&,直接拋異常
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
//若是beanInstance可能FactoryBean也多是普通的bean
//若是beanInstance是普通的bean或者僅僅是一個工廠實例 直接返回
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
//若是BeanDefinition爲null,則從factoryBeanObjectCache查找實例
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
//通過上面判斷已經肯定beanInstance是FactoryBean
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 若是bean是一個FactoryBean則緩存起來
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//這個就複雜了,主要用於當BeanDefinition的屬性值
//又是一個BeanDefinition的時候的解析賦值,後面aop還會分析
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
複製代碼
這個方法主要是獲取真正的beanInstance,當從緩存裏獲取的bean實例是一個普通的bean或者是工廠bean的時候,直接返回,但若是是FactroyBean
並且屬性值又是一個BeanDefinition
,便是一個合成bean的時候,須要調BeanPostProcessor
的實現類去解析BeanDefinition
最終生成一個bean實例,合成bean在AOP裏面很常見,分析AOP的時候會詳細說明,看到這裏,其實就已經獲取到了緩存中的bean實例對象了,不用過度關心最後一個方法,裏面無非也就是將eanDefinition
的屬性值轉換成bean實例的過程。
通過上面兩個方法,Spring已經能夠從緩存中獲取一個Bean的實例了,可是當第一次獲取bean的時候,又該怎麼處理呢,繼續往下看,首先看一個if語句裏面的方法isPrototypeCurrentlyInCreation
:
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
複製代碼
這個方法很簡單,就是在建立原型做用域的bean時首先去prototypesCurrentlyInCreation
容器中檢查是否存在beanName的bean正在建立,若是存在就拋出異常,prototypesCurrentlyInCreation
這個集合每一個線程都會保存一份,因此這裏判斷的是當前線程中名爲beanName的bean是否正在建立,由於Spring只經過提早暴露的方式解決了單例bean的循環依賴,對於Prototype模式的bean只要當前線程中存在其餘正在建立的相同的bean,就直接拋出異常,單例bean的建立只有一個線程,因此也能夠用這段代碼去校驗,看一下prototypesCurrentlyInCreation的定義就清晰了。
ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<Object>("Prototype beans currently in creation");
複製代碼
ThreadLocal
會爲每一個線程生成一個prototypesCurrentlyInCreation
集合,多個線程之間不受影響。
校驗完bean的循環依賴後,還須要將bean標記成已經建立狀態,標誌着這bean已經被建立過,下次再來獲取的時候,無需再次建立:
protected void markBeanAsCreated(String beanName) {
//alreadyCreated也是一個hashMap
this.alreadyCreated.add(beanName);
}
複製代碼
此時bean實例建立的環境條件都已知足,能夠開始建立bean了,首先須要根據beanName獲取到BeanDefinition
,下面的方法做用是獲取到BeanDefinition
,並將BeanDefinition轉換爲RootBeanDefinition:
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
//從mergedBeanDefinitions查找,該map裏面存儲的都是RootBeanDefinition
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
//若是根據beanName查詢不到RootBeanDefinition,則轉換成RootBeanDefinition
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
複製代碼
這個時候就用到了IOC第一個大步驟中生成的BeanDefinition了,在上一篇中說了BeanDefinition
裏面主要存儲了bean的類的全部信息,包括類的元素和屬性信息,接下來就是解析BeanDefinition
裏面的數據,往bean實例裏面填充就能夠了,可是首先須要獲取一個初始化後的bean實例,此時的bean應該僅僅是一個空的對象,屬性什麼的都沒有賦值。由於是針對單例的bean分析的,接下來調用getSingleton
方法,這個方法第一個參數是beanName,第二個是一個匿名內部類,bean對象實際就是由匿名內部類的實現方法createBean建立的:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
//再次嘗試從單例容器中獲取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//判斷單例IOC容器是否已經被銷燬
if (this.singletonsCurrentlyInDestruction) {
//若是單例IOC容器都被銷燬了 就直接終止bean的建立
throw new BeanCreationNotAllowedException(beanName,"不能再已經銷燬的容器中建立bean");
}
//建立前檢查 bean初始化的前置操做能夠被覆蓋,
//默認檢查當前bean是否正在建立的bena的容器中
beforeSingletonCreation(beanName);
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<Exception>();
}
try {
//核心方法最終會調用到上一個方法的匿名內部類的getObject
singletonObject = singletonFactory.getObject();
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
//將建立的bean放入到單例IOC容器中
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
複製代碼
這個方法首先是校驗了單例IOC容器是否處於存活狀態,若是已經被銷燬直接拋出異常,不容許建立該bean,而後校驗了當前bean是否已經放入到了正在建立的bean的集合中,也就是是否容許被建立,若是當前bean處於被容許被建立的集合中,調用參數ObjectFactory
的getBean()方法獲取bean對象,參數singletonFactory
是一個匿名內部類,最終會執行核心方法5:createBean(beanName, mbd, args)
這個方法去建立bean,等會就會看哪一個方法,如今加入已經經過getBean獲取到了bean實例對象,而後調用addSingleton(beanName, singletonObject)
;將當前bean註冊到單例IOC容器中。
截止到如今,終於能夠看看建立一個bean的最核心的方法createBean(beanName, mbd, args)
了,首先看看這個方法的參數,beanName是要獲取bean的name,mbd是bean的BeanDefinition對象,args是動態指定的構造函數的參數集合,固然在這個測試案例裏,args是null。createBean是一個抽象方法,由類AbstractAutowireCapableBeanFactory
實現:
@Override
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args){
//這一步主要是將配置得class轉換成Class對象
resolveBeanClass(mbd, beanName);
try {
//解析lookup-method和replaced-method方法
mbd.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
//根據mbd校驗是不是一個合成類,執行BeanPostProcessors處理器
//這裏能夠建立一個代理對象
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
//開始建立一個具體的,很單純的bean,所謂單純就是原生的bean
Object beanInstance = doCreateBean(beanName, mbd, args);
return beanInstance;
}
複製代碼
這個方法裏面其實也就是調用建立bean的方法,只不過在Spring裏面建立bean有兩種方式,一種就是原生bean的建立,另外一種就是代理bean的建立,基於代理bean的建立的入口是在 實現了BeanPostProcessor
的類中執行,這個在Spring AOP中會具體分析,這裏針對測試案例而言時須要建立原生的bean,這樣就進入到了doCreateBean
方法中:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
//初始化bean的bean最終被封裝到這個類裏
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//由於是單例,須要從緩存中移除 以後再從新生成
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//這個方法會經過查找到的構造函數初始化一個純淨的屬性未被賦值的bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
//容許修改BeanDefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
//校驗bean是否使用了循環依賴
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, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//屬性注入,爲初始化的bean設置屬性值
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//這個地方會檢查bean是否實現了一些Aware方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
throw ex;
}
//解決循環依賴問題,若是有循環依賴,從新獲取bean對象,只是參數爲false
//表示再次獲取時不容許有循環依賴問題,因爲此時已經能夠從緩存中獲取到依賴的
//bean對象,而後經過getObject()獲取便可
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<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
}
}
// 最後將生成的bean實例注入到單例IOC容器中
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
複製代碼
這個方法真正完成了生成bean的操做,代碼和複雜,可是最終完成了如下三件事情:
createBeanInstance
匹配一個合適的構造函數,經過反射建立一個bean的實例,此時的bean屬性並未賦值
populateBean
是爲生成的初始化bean設置屬性值,用於setter注入,initializeBean是method注入
通過上兩步,bean已經被實例化了,可是若是有循環依賴問題,屬性值只是一個ObjectFactroy
對象,並非一個真正對象,因此這個時候須要再次調用getSingleton
,從緩存中獲取真正的bean。
就是這三個步驟最終完成生成bean的操做,前面看了這麼多,其實都是鋪墊,這三個步驟決定了建立bena的過程,跟着上面的總結,分別來看看這三步操做時如何執行的。
若是bean有默認的無參構造函數,能夠直接經過反射初始化一個bean對象,可是若是須要使用指定的構造函數初始化一個bean,就須要去查找合適的構造函數,而後完成初始化。Spring在設置一個構造函數參數的時候,容許使用name,type,index表示一個參數,使用ref和value表示參數值,其中name和type能夠一塊兒使用,參數值ref和value只能存在一個,看下面的方法:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
//將class轉換成Class,其實上面已經轉換過了,直接就會獲取到,不會再次加載
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//若是Class不容許被實例化 直接拋出異常
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
//若是配置了factory-method,則從factory-method方法中獲取bean
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
//標識bean是否被建立而且解析過
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
//獲取beanClass的全部構造函數
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//查找合適的構造函數而後初始化bean
return autowireConstructor(beanName, mbd, ctors, args);
}
//直接使用默認無參構造函數初始化bean
return instantiateBean(beanName, mbd);
}
複製代碼
其實createBeanInstance
並無完成初始化bean操做,僅僅是針對不一樣狀況,使用了不一樣方式的初始化,好比若是bean配置了factory-method,就是使用配置的工廠方法去建立一個bean,若是beanClass構造函數列表不爲空,則先去匹配到一個構造函數,再去初始化,若是beanClass有默認的無參構造函數,則直接進行初始化便可,這裏來分析使用匹配的構造函數初始化bena的過程,測試案例中最終也會執行autowireConstructor(beanName, mbd, ctors, args)
:
protected BeanWrapper autowireConstructor( String beanName, RootBeanDefinition mbd, Constructor<?>[] ctors, Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
複製代碼
從上面代碼看來,初始化bean的操做被委託給了ConstructorResolver
的autowireConstructor
方法,說實話,這段代碼實現太長了, 都寫下來恐怕真的很複雜,分析以前仍是先簡單的介紹下這個方法的做用:
根據參數個數以及參數的name,type或者index匹配一個構造函數 初始化bean,這裏讀取構造函數參數名是使用asm讀取類的字節碼文件獲取到的。
獲取參數的真實值,在生成BeanDefinition
時候,ref的值會被保存爲RuntimeBeanReference
,value的值會被保存爲TypedStringValue
,這裏會根據不一樣的類型值使用不一樣的解析方式。
這裏仍是精簡後的代碼,只分析核心部分:
public BeanWrapper autowireConstructor( final String beanName, final RootBeanDefinition mbd, Constructor[] chosenCtors, final Object[] explicitArgs) {
//省略代碼....
//最終匹配到的要使用的構造函數
Constructor constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
//匹配到的構造函數所使用的參數列表
Object[] argsToUse = null;
//explicitArgs是在getBean(benaName,args)指定了構造函數參數列表
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
//若是未指定構造函數的參數列表,要根據配置文件去匹配合適的構造函數的參數列表
else
{
//嘗試從緩存中獲取
..........
}
//若是構造函數參數列表未指定 也沒法從緩存中獲取 讀取配置文件配置
if (constructorToUse == null) {
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
//從BeanDefinition中獲取 也就是從配置文件中獲取
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
//因爲構造函數參數可能須要轉換成真實值,用這個類接收參數值
resolvedValues = new ConstructorArgumentValues();
//將參數值放入到ConstructorArgumentValues中並返回參數個數
//這個方法會將RuntimeBeanReference,TypedStringValue等中間值解析成真實值
//等會須要看這個方法
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
//若是指定了構造函數,則從指定的構造函數中查找合適的,這裏爲null
Constructor[] candidates = chosenCtors;
if (candidates == null)
{
Class beanClass = mbd.getBeanClass();
try {
//獲取bean實例的全部構造函數
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
//bean不能被實例化 沒法獲取構造函數 拋出異常
throw ex;
}
}
//根據構造函數參數個數進行排序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor> ambiguousConstructors = null;
List<Exception> causes = null;
//遍歷bean的全部構造函數 最終找到一個合適的構造函數
for (int i = 0; i < candidates.length; i++) {
Constructor<?> candidate = candidates[i];
Class[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
//由於前面已經對構造函數參數根據參數個數進行排序,因此若是當前的參數
//個數都不知足,後面的構造函數參數個數確定不知足 直接中斷循環便可
break;
}
//若是
if (paramTypes.length < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
//下面這個執行體裏主要是經過asm獲取構造函數的方法參數名
//根據參數名和參數類型去檢索出一個合適的構造函數
if (resolvedValues != null) {
try {
String[] paramNames = null;
if (constructorPropertiesAnnotationAvailable) {
paramNames = ConstructorPropertiesChecker.evaluateAnnotation(candidate, paramTypes.length);
}
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
}
catch (UnsatisfiedDependencyException ex) {
throw ex;
}
else {
//根據傳入的參數列表 獲取一個構造函數
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 若是匹配到了就選擇這個構造函數 並將參數值賦予到
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<Constructor>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
//省略一些代碼......
Object beanInstance;
if (System.getSecurityManager() != null) {
.........
}
else {
//最終根據選擇構造函數和參數列表 初始化一個bean實例
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
bw.setWrappedInstance(beanInstance);
return bw;
}
}
複製代碼
這段代碼很長,真想看明白仍是建議經過斷點調試的方式一點一點看裏面的內容,針對這裏面的不少方法不在具體分析,這個代碼其實就完成了一個功能,匹配構造函數,只不過這裏分了三種狀況,若是指定了構造參數explicitArgs
,則使用,若是未指定則從緩存中讀取,若是還未讀取到則從BeanDefinition獲取,最終獲取到要使用的構造函數參數,而後獲取bean的全部構造函數,根據參數name和type去匹配一個構造函數,最終初始化一個bean。在建立BeanDefinition
的時候,屬性值或者參數值是經過RuntimeBeanReference
等中間類表示的,在下面的方法裏就會將這些中間類解析成真正的值:
public Object resolveValueIfNecessary(Object argName, Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(evaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException(
"Invalid bean name '" + refName + "' in bean reference for " + argName);
}
return refName;
}
else if (value instanceof BeanDefinitionHolder) {
// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}
else if (value instanceof BeanDefinition) {
// Resolve plain BeanDefinition, without contained name: use dummy name.
BeanDefinition bd = (BeanDefinition) value;
return resolveInnerBean(argName, "(inner bean)", bd);
}
.........
}
複製代碼
這個方法會將中間類最終轉換成實際的值,這裏面有不少類型,能夠支持更復雜的BeanDefinition
參數的解析。
通過上面分析,Spring會爲bean匹配一個構造函數,而後獲得初始化後的bean,此時的bean只是一個很"單純"的bean,所謂單純也就是bean並無完成實例化操做,也就是沒有把相關屬性值注入到這個bean的屬性中,下面的方法就是完成屬性注入的,屬性注入通常有兩種方式,一種是經過name注入也就是autowireByName
,還有一種是根據類型注入,也就是autowireByType
。
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!pvs.isEmpty()) {
//若是bw爲空 並且mbd裏面有配置的屬性,表明初始化失敗,直接拋出異常
}
else {
//初始化失敗 沒有要注入的屬性 繼續直接返回
return;
}
}
//執行 BeanPostProcessor 若是有的話,這個是在bean進行屬性設置以前對bean注入
//好比經過註解的方式進行屬性注入就是在這裏完成的
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 經過屬性name注入值
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 經過屬性的classType爲屬性注入值
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
//這部分也執行BeanPostProcessor
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
//最終在這個方法裏面完成屬性的設置的
applyPropertyValues(beanName, mbd, bw, pvs);
}
複製代碼
這個方法其實就是從BeanDefinition中獲取配置的屬性值,首先會經過BeanPostProcessor
實現的類解析經過註解設置的屬性,而後再解析經過配置文件配置的屬性,注入屬性有兩種方式autowireByName
和autowireByType
,這個過程其實就是將BeanDefinition
引用的中間值轉換成真實值的過程,而後經過applyPropertyValues
使用真實值對初始化的bean進行實例化。思路其實很簡單,spring將經過註解的方式注入屬性的邏輯放入到了BeanPostProcessor
中,複雜的邏輯其實在BeanPostProcessor
中,哪一個實現比起分析的基於xml配置的實現,封裝性要更強一點,可是最終達到的效果是同樣的,理解了基於xml配置的屬性注入方式,基於註解的配置只要耐心的看,也很容易理解,屬性注入的代碼其實沒什麼好分析的。主要看下autowireByType
和autowireByType
,這兩個方法若是是基於xml的須要配置autowire
屬性,分別對應byName和byType,可是仍是要對比看看spring是如何實現的,首先autowireByType
:
protected void autowireByName( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//獲取註解的全部屬性name
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
//判斷容器中是否包含name的實例
if (containsBean(propertyName)) {
//若是直接包含 直接獲取該實例便可
Object bean = getBean(propertyName);
//將實例添加到bean的屬性集合裏 等到注入
pvs.add(propertyName, bean);
//因爲建立當前bena的時候,屬性實例也被附帶建立了,因此要註冊到IOC容器中
registerDependentBean(propertyName, beanName);
}
else {
//IOC容器中沒有對應name的屬性值
}
}
}
複製代碼
基於name去獲取bean實例從代碼上看很是簡單,僅僅是經過name從IOC中獲取屬性名爲propertyName
的實例。若是趙傲則放入到bean實例的屬性參數集合中,等到被注入便可。與autowireByType
相比,autowireByType
可就複雜多了,複雜的緣由就是要解析依賴項的過程。
protected void autowireByType( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
//若是屬性類型爲object 直接忽略就行
if (!Object.class.equals(pd.getPropertyType())) {
//獲取 setter 方法(write method)的參數信息,好比參數在參數列表中的
//位置,參數類型,以及該參數所歸屬的方法等信息
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());
//建立屬性依賴描述對象 這裏麪包含了字段類型 字段名 已是否必輸等信息
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
//解析屬性依賴。獲取bean對象 這裏面比較複雜 是主要查找過程
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
registerDependentBean(autowiredBeanName, beanName);
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
複製代碼
如上所示,autowireByType
的代碼自己並不複雜。和 autowireByName
同樣,autowireByType
首先也是獲取非簡單類型屬性的名稱。而後再根據屬性名獲取屬性描述符,並由屬性描述符獲取方法參數對象 MethodParameter
,隨後再根據 MethodParameter
對象獲取依賴描述符對象,在獲取到依賴描述符對象後,再根據依賴描述符解析出合適的依賴。最後將解析出的結果存入屬性列表 pvs 中便可,核心的解析依賴對象在方法resolveDependency
中,這裏就不展開分析了,感興趣的能夠調試看下。
通過上面的分析,Spring經過autowireConstructor
方法完成bean的初始化,經過populateBean
完成bean的屬性注入(實例化),這只是最基本的bean的建立過程,在Spring中還有一些與bean生命週期相關的Aware接口,以及實例化後調用init-method
指定的方法的過程,回頭看下populateBean
以後的代碼,這段代碼在doCreateBean
中:
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//這個方法會檢查bean是否實現了Aware接口 是否指定了init-method方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
複製代碼
查看initializeBean方法
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
//檢查是否實現了Aware接口
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
//檢查是否實現了Aware接口
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//執行BeanPostProcessor的postProcessBeforeInitialization
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//查找是否指定了init-method方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//執行BeanPostProcessor的postProcessAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
複製代碼
在這個方法中,主要作的事情能夠歸納爲如下四步:
首先會調用invokeAwareMethods
檢查bean是否實現了Aware接口,若是實現了就調用Aware接口,
調用applyBeanPostProcessorsBeforeInitialization
方法,這個方法也是在bean建立的生命週期中,是bean在屬性填充完畢以後在bean初始化方法調用以前執行,其實是調用的BeanPostProcessor
的postProcessBeforeInitialization
方法
調用invokeInitMethods
去檢查bean是否指定了init-method
方法,若是指定了就執行
調用applyBeanPostProcessorsAfterInitialization
,對應的是調用BeanPostProcessor
的postProcessAfterInitialization
方法
接下來主要看看invokeAwareMethods
和invokeInitMethods
這兩個方法:
private void invokeAwareMethods(final String beanName, final Object bean) {
//檢查bena是否實現了對應的Aware接口
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
複製代碼
下面的方法是檢查bean是否指定了init-method
方法
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
//判斷bean的屬性是否由BeanFactoryAware或者BeanFactory等建立
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//調用bean的afterPropertiesSet再次解析bean的屬性
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
//查看是否指定了init-method
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//若是指定了就執行init-method方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
複製代碼
前面已經簡單說過Spring是如何解決循環依賴問題,因爲上面主要是分析Spring源碼的過程,可能說的不是那麼清晰,我以爲有必要將這部份內容單獨拿出來講一說。
通過前面的步驟,已經能夠獲取到一個通過初始化的bean實例,並且完成了bean的屬性注入,可是前面還有一個問題沒有解決,若是在單例IOC中有循環依賴,暫時是用ObjectFactory
中間類代替的,因此還要經過ObjectFactory
的getObject
方法獲取真正的bean,此時全部的bean已經被建立完成,因此經過getBean
能夠獲取到真實的bean實例對象,再看看下面的代碼,這段代碼也是在doCreateBean
中:
//解決循環依賴問題,若是有循環依賴,從新獲取bean對象,只是參數爲false
//表示再次獲取時不容許有循環依賴問題,因爲此時已經能夠從緩存中獲取到依賴的
//bean對象,而後經過getObject()獲取便可
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<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
}
}
複製代碼
Spring解決循環依賴是經過ObjectFactory
中間類實現的,固然經過這個類只能解決單例IOC的屬性循環依賴的問題,對於原型模式和構造器的循環以來,spring至今也沒有解決方法,首先來回顧一下Spring獲取一個bean的簡單過程:
singletonObjects
獲取,也就是單例IOC容器中earlySingletonObjects
中獲取,也就是經過ObjectFactory
實現的提早曝光的容器singletonFactories
獲取,也就是實例化bean的實例工廠 從緩存中獲取的bean的過程,網上不少都叫三級緩存,前面三個步驟對應了1,2,3級緩存。接下來舉一個案例分析這個過程,假若有bean的依賴關係爲:A->B->C->A,固然這些都是基於屬性依賴的,當A執行到populateBean
方法實現屬性注入的時候,會先去獲取B實例,而後B執行populateBean
會獲取C實例,C執行到populateBean
獲取查找A實例,此時A實例正在被建立,又會循環上述過程,產生了循環依賴問題。Spring獲取getBean()
最終調用下面簡化後的方法:
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;
//關注點1
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
try {
if (mbd.isSingleton()) {
//關注點2
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);
}
..............
}
return (T) bean;
}
複製代碼
當A去查找bean的實例的時候,會調用上面的doGetBean
方法獲取,這個方法裏面有兩個關注點,分別是兩個重載方法getSingleton
,首先當A執行populateBean
查找B的實例時調用第一個重載:
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,第一級緩存singletonObjects
裏面放置的是實例化好的單例對象。第二級earlySingletonObjects
裏面存放的是提早曝光的單例對象(沒有徹底裝配好)。第三級singletonFactories
裏面存放的是要被實例化的對象的對象工廠,因爲B第一次獲取尚未被建立,因此一級緩存singletonObjects
獲取結果確定爲null,再看看看看進入二級緩存中的條件isSingletonCurrentlyInCreation(beanName)
:
public boolean isSingletonCurrentlyInCreation(String beanName) {
//在這裏表示bean是否正在建立的過程,此時B 還沒有在建立中,因此會返回false
return this.singletonsCurrentlyInCreation.contains(beanName);
}
複製代碼
上面的步驟中並無任何操做往isSingletonCurrentlyInCreation
中加入B的beanName的操做,因此壓根不會進入二級緩存,直接就返回null了,而後就判斷bean是否時單例的,若是時調用getSingleton(String beanName, ObjectFactory objectFactory)
,此時objectFactory時一個匿名內部類,實例B的獲取是經過內部類的createBean
獲取的,這個是咱們關注點2 :
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
//從一級緩存中獲取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,"不能從銷燬的bean中建立");
}
//在這裏將B的beanName添加到isSingletonCurrentlyInCreation
beforeSingletonCreation(beanName);
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<Exception>();
}
try {
//最終調用匿名內部類建立bean
singletonObject = singletonFactory.getObject();
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
複製代碼
這個方法首先會從一級緩存中查找B,很明顯,查到的結果爲null,而後調用beforeSingletonCreation(beanName)
,將B的beanName添加到singletonsCurrentlyInCreation
中,也就是關注點1中沒法進入二級緩存的那個集合校驗:
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) &&
!this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
複製代碼
緊接着就會調用singletonFactory.getObject()
建立名,也就是經過匿名內部類的createBean
方法建立,前面分析過,建立bean最終會調用doCreateBean
方法,這個方法簡化了, 只看最核心的關注點3:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...........代碼省略...........
//關注點3
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, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
//初始化和實例化bean
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
throw 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<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
}
}
}
...........代碼省略...........
return exposedObject;
}
複製代碼
createBeanInstance
利用反射建立了對象,下面咱們看看關注點3earlySingletonExposure
屬性值的判斷,其中有一個判斷點就是isSingletonCurrentlyInCreation(beanName)
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
複製代碼
發現使用的是singletonsCurrentlyInCreation
這個集合,在上面的步驟中將的B的BeanName已經填充進去了,因此能夠查到,並且在初始化bean的時候,還會判斷檢查bean是否有循環依賴,並且是否容許循環依賴,這裏的ABC造成了循環依賴,因此最終earlySingletonExposure
結合其餘的條件綜合判斷爲true,進行下面的流程addSingletonFactory
,這裏是爲這個Bean添加ObjectFactory
,這個BeanName(A)
對應的對象工廠,他的getObject
方法的實現是經過getEarlyBeanReference
這個方法實現的。首先咱們看下addSingletonFactory
的實現
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);
}
}
}
複製代碼
往三級緩存singletonFactories
存放數據,清除二級緩存中beanName對應的數據。這裏有個很重要的點,是往三級緩存裏面存入了值,這是Spring處理循環依賴的核心點。getEarlyBeanReference
這個方法是getObject
的實現,能夠簡單認爲是返回了一個爲填充完畢的A的對象實例。設置完三級緩存後,就開始了填充A對象屬性的過程。
上面理清以後總體來分析如下ABC的初始化流程,當設置A的屬性時,發現須要B類型的Bean,因而繼續調用getBean
方法建立,此次的流程和上面A的徹底一致,而後到了填充C類型的Bean的過程,一樣的調用getBean(C)來執行,一樣到了填充屬性A的時候,調用了getBean(A),咱們從這裏繼續說,調用了doGetBean中的`Object sharedInstance = getSingleton(beanName),仍是關注點1的代碼,可是處理邏輯徹底不同了。
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) {
//從三級緩存中獲取 此時能夠獲取到 A 的實例,雖然屬性並不太完整
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
複製代碼
仍是從singletonObjects獲取對象獲取不到,由於A是在singletonsCurrentlyInCreation
這個Set中,因此進入了下面的邏輯,從二級緩存earlySingletonObjects
中取,仍是沒有查到,而後從三級緩存singletonFactories
找到對應的對象工廠調用getObject
方法獲取未徹底填充完畢的A的實例對象,而後刪除三級緩存的數據,填充二級緩存的數據,返回這個對象A。C依賴A的實例填充完畢了,雖然這個A是不完整的。無論怎麼樣C式填充完了,就能夠將C放到一級緩存singletonObjects
同時清理二級和三級緩存的數據。一樣的流程B依賴的C填充好了,B也就填充好了,同理A依賴的B填充好了,A也就填充好了。Spring就是經過這種方式來解決循環引用的。
經過上面的代碼分析,Spring經過BeanFactory
的getBean()
方法獲取bean實例的大體流程爲:
從緩存中獲取bean實例(三級緩存 解決循環依賴問題)
若是bean沒有被建立過,執行建立bean的流程
autowireConstructor
匹配構造函數,經過反射建立一個bean實例
經過populateBean
完成bean的屬性注入
經過initializeBean
檢查bean配置得初始化方法和Aware接口
將建立得bean加入到IOC容器中
實際上,若是不考慮註解的話 ,Spring解析配置文件並完成bean的建立過程,就是上面的那部分代碼,沒有太多複雜的算法和抽象結構,很容易理解。Spring把不少解析註解的邏輯放入到了BeanPostProcessor
中執行並經過這些實現類控制了bean的生命週期,在每一個生成BeanDefinition或者getBean()的關鍵方法中,總會在方法前或後執行這些接口方法,這些接口最終會調用到封裝好的功能,好比經過註解聲明類和屬性注入還有AOP的方法攔截。若是想了解這部分的實現,能夠看下BeanPostProcessor接口的實現類,主要功能在那裏封裝的,內容比較抽象,但仍是很值得看的。到此爲止,Spring IOC的原理基本上就分析完了,接下來會分析Spring AOP的部分。