前文「spring 如何從 ioc 容器中獲取物件?」從整體上分析了如何從 spring ioc 容器獲取乙個 bean 物件。該邏輯由 abstractbeanfactory#dogetbean 方法實現,主要流程如下:
本文進一步深入細節,主要分析如何建立 singleton(單例)型別的物件。
從流程圖可以看出,當獲取乙個 bean 物件時,spring 會首先嘗試從快取中獲取單例物件。
值得注意是的:既然能取,必然有地方把 bean 物件存入了快取,那快取中的資料是從**來的呢?只有物件是單例的場景,即 scope 為 singleton 時才會快取物件。
這裡其實涉及到了所謂的「**快取」,為了更容易理解**快取,本文先研究這個 bean 物件是什麼時候放入快取的,後面再研究**快取。
下面主要分析單例物件是如何建立、並放入快取中的。
該邏輯在 abstractbeanfactory#dogetbean 方法中,主要**如下(保留了建立單例 bean 物件的**,其他部分暫時忽略):
public abstract class abstractbeanfactory extends factorybeanregistrysupport implements configurablebeanfactory
catch (bean***ception ex)
});// 處理 factorybean 的場景
bean = getobjectforbeaninstance(sharedinstance, name, beanname, mbd);
}// 建立 scope 為 prototype 的物件
else if (mbd.isprototype())
// 建立其他型別物件
else
}catch (bean***ception ex)
}// 型別檢查
return (t) bean;}}
其實就是這個 defaultsingletonbeanregistry#getsingleton 方法,**如下:
public class defaultsingletonbeanregistry extends ******aliasregistry implements singletonbeanregistry
try
// catch ...
finally
// 建立單例物件後
aftersingletoncreation(beanname);
}if (newsingleton)
}// 快取中有的話直接返回
return singletonobject;}}
}
getsingleton 方法會先從快取 singletonobjects(其實就是乙個 map)中獲取 bean 物件,如果快取有就直接返回,否則再去建立。建立成功後,會把該物件存入快取。
建立的邏輯在哪呢?
看**是通過 objectfactory#getobject 方法來建立的,objectfactory 是乙個函式式介面:
@functionalinte***ce
public inte***ce objectfactory
sharedinstance = getsingleton(beanname, () ->
catch (bean***ception ex)
});
這裡用到了 lambda 表示式,將如下表示式作為引數:
() ->
catch (bean***ception ex)
}
建立 bean 物件的邏輯就在這個 createbean 方法中,它在 abstractautowirecapablebeanfactory 類中:
public abstract class abstractautowirecapablebeanfactory extends abstractbeanfactory
implements autowirecapablebeanfactory
// prepare method overrides.
try
// catch ...
try
}// catch ...
try
return beaninstance;
}// catch ...}}
值得注意的是,resolvebeforeinstantiation 方法其實是跟 aop 實現相關的,可能在這裡生成**物件就返回了。由於現在主要分析 ioc 的流程,因此這裡暫時略過,有興趣的朋友們可以自行研究。這裡繼續沿著主線邏輯走。
建立 bean 物件是在 docreatebean 方法中實現的,如下:
public abstract class abstractautowirecapablebeanfactory extends abstractbeanfactory
implements autowirecapablebeanfactory
}if (beantype != nullbean.class)
// allow post-processors to modify the merged bean definition.
synchronized (mbd.postprocessinglock)
// catch ...
mbd.postprocessed = true;}}
boolean earlysingletonexposure = (mbd.issingleton() && this.allowcircularreferences &&
issingletoncurrentlyincreation(beanname));
if (earlysingletonexposure)
// initialize the bean instance.
object exposedobject = bean;
try
// catch ...
if (earlysingletonexposure)
string dependentbeans = getdependentbeans(beanname);
setactualdependentbeans = new linkedhashset<>(dependentbeans.length);
for (string dependentbean : dependentbeans)
}// ...}}
}// register bean as disposable.
try
// catch ...
return exposedobject;}}
注意:instantiate 和 initialize 雖然看起來有點像,但它倆不是一回事,前者是「例項化」,後者是「初始化」。這個方法看起來有點長,但最主要的事情只有三件:
建立 bean 物件:createbeaninstance 方法
填充屬性:populatebean 方法
初始化 bean:initializebean 方法
這幾個方法內部其實都有一大堆堆堆堆堆……的**,再對照一下前面給出的整體流程圖:
就是這樣。
本文在前文整體分析的基礎上又進一步細化,先到這裡吧,後面再繼續分析~
如何從 spring ioc 容器中獲取 bean 物件?前文對此進行了整體流程的分析。
建立 bean 物件
填充 bean 屬性
初始化 bean 物件
至於這三個步驟具體又做了什麼,且聽下回分解。
有點「自頂向下」的感覺了,這就是「金字塔原理」?
Spring動態建立bean
最近有個專案場景,多垂類支援,大體業務流程相同,只是一些業務規則的校驗引數不同。解決思路是將業務引數作為類的屬性,然後建立垂類數量個例項,去處理不同垂類的業務。下面分兩部分介紹 1 動態建立bean的 實現 2 spring的ioc原始碼解讀,這部分放到另外一篇部落格 url 4.0.6.relea...
Spring對Bean裝配過程
color red spring裝配bean的過程 color 1.例項化 2.設定屬性值 3.如果實現了beannameaware介面,呼叫setbeanname設定bean的id或者name 4.如果實現beanfactoryaware介面,呼叫setbeanfactory 設定beanfact...
spring建立bean的方式
spring建立bean主要有三種方式 方式一 使用預設的構造方法 實體類 package com.lzcc.instancefactorymethod 資料訪問物件層 author version v 1.00 2014 4 20 author updatetime updatecontent p...