Spring Ioc原始碼分析系列--Bean例項化過程(一)
前言
上一篇文章Spring Ioc原始碼分析系列--Ioc容器註冊BeanPostProcessor後置處理器以及事件訊息處理已經完成了對IoC容器啟動方法也就是refresh()
方法的簡單分析。但是之前的分析在對容器例項化Bean的過程的略過了,留到了這後續的文章分析,所以這篇文章會對Bean的例項化過程做一個介紹。
首先來理一下本文的思路:關鍵詞是例項化。由於Spring是利用反射實現的例項化,腦子裡先簡單想一下Java裡利用發射例項化一個物件需要哪些步驟和操作。毫無疑問,我們首先要知道物件的class
,接著需要確定使用什麼建構函式以及確定建構函式的引數等。利用這些已經基本可以實現一個物件的例項化,當然實際上需要的東西可能更多更復雜,這裡只是舉個例子。那麼需要的這些資訊可以去哪裡提取呢?對Spring有了解的可能都馬上能想到BeanDefinition
,這是一份原料表,裡面有我們構造一個例項化物件所需的所有引數。如果不太理解這個定義,可以參考一下上篇文章的例子。
如果不清楚BeanDefinition是從哪裡來的以及不清楚如何定義的,可以參考之前的文章Spring Ioc原始碼分析系列--Ioc原始碼入口分析的關鍵實現系列方法 loadBeanDefinitions ()
。這篇文章講解註冊的時候只是說了註冊到容器裡,並沒有說明具體是註冊到了哪裡,這裡點明一下,所謂講BeanDefinition
註冊到容器裡,就是將BeanDefinition
放入到容器的一個Map裡,具體是註冊到了DefaultListableBeanFactory
的beanDefinitionMap
屬性裡,beanName
會儲存到beanDefinitionNames
屬性裡,這是個list
集合,裡面的beanName
會保持註冊時候的順序。
例項化的開始就是從遍歷所有的beanName
開始,話不多說,開始分析吧。
原始碼分析
bean例項化入口
還記得例項化入口的方法名嗎?回憶一下,算了,反正也不會有人記得。是beanFactory.preInstantiateSingletons()
,具體實現是在DefaultListableBeanFactory
類裡。
跟進程式碼檢視,可以看到,這段程式碼分為兩部分,第一個for迴圈用於先例項化物件,第二個for迴圈完成一些例項化之後的回撥操作。我們先來看第一個for迴圈,首先是遍歷所有的beanNames
獲取BeanDefinition
,然後根據工廠bean
和非工廠bean
進行相應處理,最後呼叫getBean(beanName)
例項化物件。注意這裡例項化的是非抽象的、單例的並且是非懶載入的bean,這個前提非常重要。
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 所有bd的名稱
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 遍歷所有bd,一個個進行建立
for (String beanName : beanNames) {
// 獲取到指定名稱對應的bd
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 對不是延遲載入的單例的Bean進行建立
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 判斷是否是一個FactoryBean
if (isFactoryBean(beanName)) {
// 如果是一個factoryBean的話,先建立這個factoryBean,建立factoryBean時,需要在beanName前面拼接一個&符號
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
// 判斷是否是一個SmartFactoryBean,並且不是懶載入的,就意味著,在建立了這個factoryBean之後要立馬呼叫它的getObject方法建立另外一個Bean
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 不是factoryBean的話,我們直接建立就行了
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// 在建立了所有的Bean之後,遍歷為所有適用的 bean 觸發初始化後回撥,也就是這裡會對延遲初始化的bean進行載入...
for (String beanName : beanNames) {
// 這一步其實是從快取中獲取對應的建立的Bean,這裡獲取到的必定是單例的
Object singletonInstance = getSingleton(beanName);
// 判斷是否是一個SmartInitializingSingleton,
// 最典型的就是我們之前分析過的EventListenerMethodProcessor,
// 在這一步完成了對已經建立好的Bean的解析,會判斷其方法上是否有 @EventListener註解,
// 會將這個註解標註的方法通過EventListenerFactory轉換成一個事件監聽器並新增到監聽器的集合中
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
獲取BeanDefinition
首先跟進getMergedLocalBeanDefinition(beanName)
方法,這裡首先會嘗試從mergedBeanDefinitions
裡去獲取,這個mergedBeanDefinitions
存放著已經合併過的BeanDefinition
,獲取不到再真正呼叫getMergedBeanDefinition(beanName, getBeanDefinition(beanName))
去獲取。
/**
* Return a merged RootBeanDefinition, traversing the parent bean definition
* if the specified bean corresponds to a child bean definition.
*
* 返回一個合併的 RootBeanDefinition,如果指定的 bean 對應於子 bean 定義,則遍歷父 bean 定義。
*
* @param beanName the name of the bean to retrieve the merged definition for
* @return a (potentially merged) RootBeanDefinition for the given bean
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
* @throws BeanDefinitionStoreException in case of an invalid bean definition
*/
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
// 首先檢查 mergedBeanDefinitions ,最小程度影響併發效能
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
先看getBeanDefinition(beanName)
,這個方法就是簡單的去beanDefinitionMap
裡獲取BeanDefinition
,如果獲取不到,就丟擲異常。beanDefinitionMap
就是上面說到的BeanDefinition
存放的地方。
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
if (logger.isTraceEnabled()) {
logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
接下來就進入到getMergedBeanDefinition()
方法獲取BeanDefinition
,為啥要從beanDefinitionMap
獲取了還進行一個merged獲取呢?這是因為Bean有層次關係,子類需要合併父類的屬性方法等,所以要進行一次合併,合併完成後會放入到mergedBeanDefinitions
裡,功能和屬性名區分度還是十分貼切的?。
跟進方法,程式碼已新增註釋,比較簡單,跟著看看就行。
/**
* Return a RootBeanDefinition for the given top-level bean, by merging with
* the parent if the given bean's definition is a child bean definition.
*
* 如果給定 bean 的定義是子 bean 定義,則通過與父級合併返回給定頂級 bean 的 RootBeanDefinition。
*
* @param beanName the name of the bean definition
* @param bd the original bean definition (Root/ChildBeanDefinition)
* @return a (potentially merged) RootBeanDefinition for the given bean
* @throws BeanDefinitionStoreException in case of an invalid bean definition
*/
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
/**
* Return a RootBeanDefinition for the given bean, by merging with the
* parent if the given bean's definition is a child bean definition.
*
* 如果給定 bean 的定義是子 bean 定義,則通過與父合併返回給定 bean 的 RootBeanDefinition
*
* @param beanName the name of the bean definition
* @param bd the original bean definition (Root/ChildBeanDefinition)
* @param containingBd the containing bean definition in case of inner bean,
* or {@code null} in case of a top-level bean
* 如果是內部 bean,則包含 bean 定義,如果是頂級 bean,則為 {@code null}
* @return a (potentially merged) RootBeanDefinition for the given bean
* @throws BeanDefinitionStoreException in case of an invalid bean definition
*/
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
// 現在檢查完全鎖定以強制執行相同的合併例項。
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
mbd = null;
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
// 使用給定根 bean 定義的副本。
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
// Child bean definition: needs to be merged with parent.
// 子bean定義:需要與父合併。
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
// 具有覆蓋值的深拷貝。
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
// 如果之前未配置,則設定預設單例範圍。
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
// 包含在非單例 bean 中的 bean 本身不能是單例。
// 讓我們在這裡即時糾正這個問題,因為這可能是外部 bean 的父子合併的結果,
// 在這種情況下,原始內部 bean 定義將不會繼承合併的外部 bean 的單例狀態。
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
// 暫時快取合併的 bean 定義(它可能稍後仍會重新合併以獲取後設資料更改)
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
建立Bean
獲取BeanDefinition
完成後,接下來就呼叫getBean(beanName)
進行bean的例項化了。當然這裡的建立還是分了工廠Bean和非工廠Bean兩個邏輯,如果是一個工廠Bean,那麼getBean(beanName)
這一步只會建立一個工廠Bean,接下來會通過isEagerInit
引數判斷是否需要初始化工廠Bean的物件,如果需要,再呼叫getBean(beanName)
去立馬獲取工廠Bean需要生產的物件。不是工廠Bean的話,直接一步到位建立物件了,少一分曲折。
跟進程式碼檢視,可以看到真正的執行程式碼的是在doGetBean()
方法裡。跟進doGetBean()
方法,發現程式碼非常的長,這裡我會把這個方法切分成幾塊去解析。
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
由於程式碼量比較大,這裡貼一張圖,展示各個部分間的作用,然後對每個部分進行逐步分析。
看起來是不是很簡單,其實每一部分都包含了大量的細節操作,先來看第一步的名稱轉換,這個比較簡單。
名稱轉換
這一步就是把&
開頭的name
轉換成不帶&
的name
。
/**
* Return the bean name, stripping out the factory dereference prefix if necessary,
* and resolving aliases to canonical names.
*
* 返回 bean 名稱,必要時去除工廠取消引用字首,並將別名解析為規範名稱。
*
* @param name the user-specified name
* @return the transformed bean name
*/
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
可以看到這裡會有個迴圈去處理,帶有多個&的都會被去掉。
/**
* Return the actual bean name, stripping out the factory dereference
* prefix (if any, also stripping repeated factory prefixes if found).
*
* 返回實際的 bean 名稱,去除工廠取消引用字首(如果有,也去除重複的工廠字首,如果找到)。
*
* @param name the name of the bean
* @return the transformed name
* @see BeanFactory#FACTORY_BEAN_PREFIX
*/
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
確定名稱,一個Bean可能會有很多委派的別名,這個時候需要確定最根本的那個name
,用這個最根本的name
來作為beanName
去進行後續的操作,這裡同樣有個迴圈去處理,因為別名也會有多重,會存在別名的別名這種情況。
/**
* Determine the raw name, resolving aliases to canonical names.
* 確定原始名稱,將別名解析為規範名稱。
* @param name the user-specified name
* @return the transformed name
*/
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
// 處理別名...
String resolvedName;
do {
// 可能會有別名層層巢狀的情況,所以需要獲取到最終的名稱
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
從容器快取中獲取Bean
在上一步中我們已經獲取到了真正的beanName
,那麼接下來,就可以利用這個beanName
到容器的快取中嘗試獲取bean,如果之前已經建立過,這裡就可以直接獲取到bean。這裡的快取包括三級,但是這三級快取並不是包含的關係,而是一種互斥的關係,一個bean無論處於何種狀態,它在同一時刻只能處於某個快取當中。
跟進getSingleton(beanName)
方法程式碼。
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
可以看到這裡預設給多了一個引數為true
,這引數為allowEarlyReference
,用來控制是否允許迴圈依賴。方法程式碼註釋比較詳細,就是逐個快取去獲取,跟著看一下問題不大。第一次進來肯定是獲取不到任何東西的,所以這裡會返回null
。
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
*
* 返回在給定名稱下注冊的(原始)單例物件。
* <p>檢查已經例項化的單例,並允許提前引用當前建立的單例(解決迴圈引用)。
*
* @param beanName the name of the bean to look for 要查詢的 bean 的名稱
* @param allowEarlyReference whether early references should be created or not 是否應建立早期引用
* @return the registered singleton object, or {@code null} if none found 註冊的單例物件,如果沒有找到則為 {@code null}
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 檢測一級快取中是否存在例項
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 如果為空,則鎖定全域性變數進行處理
synchronized (this.singletonObjects) {
// 從二級快取 earlySingletonObjects 中獲取
singletonObject = this.earlySingletonObjects.get(beanName);
// 二級快取中沒有,並且 allowEarlyReference = true 允許提前建立早期引用,則到三級快取中獲取
// 早期引用一般是用來指向需要經過代理的bean或者是需要延遲初始化的bean
if (singletonObject == null && allowEarlyReference) {
// 當某些方法需要提前初始化的時候,則會呼叫addSingletonFactory方法
// 將對應的objectFactory初始化策略儲存在singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 這裡的實現是一個lambada表示式,具體的實現有很多種
// 呼叫預先設定的getObject方法,也就是呼叫之前加入的 getEarlyBeanReference()方法
// 此表示式是在 doCreateBean() 方法中呼叫 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)) 加入的
singletonObject = singletonFactory.getObject();
// 將bean加入二級快取中
this.earlySingletonObjects.put(beanName, singletonObject);
// 同時從三級快取中將bean移除,也就是移除一個ObjectFactory,對應為一個lambada表示式
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
快取存在bean
這裡講解的是截圖的第三部分,程式碼是第260行到276行左右。
if (sharedInstance != null && args == null) {
// 省略部分日誌...
// 如果直接從單例池中獲取到了這個 bean(sharedInstance),我們能直接返回嗎?
// 當然不能,因為獲取到的 Bean 可能是一個 factoryBean,
// 如果我們傳入的 name 是 & + beanName 這種形式的話,
// 那是可以返回的,但是我們傳入的更可能是一個 beanName,
// 那麼這個時候 Spring 就還需要呼叫這個 sharedInstance 的 getObject 方法來建立真正被需要的 Bean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
可以看到,去除日誌後,只剩下一個主要的方法,跟進getObjectForBeanInstance()
程式碼檢視。可以看到這裡會進行一些型別的判斷,會嘗試從快取獲取,最後會呼叫getObjectFromFactoryBean
方法從FactoryBean
裡獲取例項物件。
/**
* Get the object for the given bean instance, either the bean
* instance itself or its created object in case of a FactoryBean.
*
* 獲取給定 bean 例項的物件,bean 例項本身或其建立的物件(如果是 FactoryBean)。
*
* @param beanInstance the shared bean instance
* @param name name that may include factory dereference prefix
* @param beanName the canonical bean name
* @param mbd the merged bean definition
* @return the object to expose for the bean
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 如果指定的name是工廠相關(以&為字首)且 beanInstance又不是FactoryBean型別則驗證不通過
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 現在我們有了 bean 例項,它可能是普通的 bean 或 FactoryBean。
// 如果它是一個 FactoryBean,我們使用它來建立一個 bean 例項,除非呼叫者實際上想要一個對工廠的引用。
// 如果是普通bean,直接返回了
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
//載入factoryBean
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//嘗試從快取中獲取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
// 到這裡可以確定 beanInstance 一定是 FactoryBean 型別
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
// 如果是單例,則快取從 FactoryBean 獲得的物件。
// containsBeanDefinition 檢測 beanDefinitionMap 中也就是在所有已經載入的類中檢測是否定義 beanName
if (mbd == null && containsBeanDefinition(beanName)) {
// 將儲存XML檔案的 GenericBeanDefinition 轉換為 RootBeanDefinition,如果指定的 beanName 是子 bean 的話
// 會同時合併父類的相關屬性
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否是用使用者自己定義的還是用程式本身定義的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
跟進getObjectFromFactoryBean()
方法,該方法首先也是從快取獲取,然後呼叫doGetObjectFromFactoryBean()
真正獲取bean物件,這裡會區分單例和原型分別去獲取,單例獲取完成後會放入快取,原型則每次都新建,所以原型bean的建立前前後後會省略很多步驟。獲取完成後根據shouldPostProcess
判斷是否需要後置處理,從而執行BeanPostProcessor#postProcessAfterInitialization()
後置處理器的方法,最後將物件放入快取中。這些處理思路跟我們平時寫業務程式碼的思路也是非常類似的,可以互相借鑑一下。
/**
* Obtain an object to expose from the given FactoryBean.
*
* 從給定的 FactoryBean 中獲取要公開的物件。
*
* @param factory the FactoryBean instance
* @param beanName the name of the bean
* @param shouldPostProcess whether the bean is subject to post-processing bean是否經過後處理
* @return the object obtained from the FactoryBean
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//如果是單例的話
if (factory.isSingleton() && containsSingleton(beanName)) {
//加鎖,保證單例
synchronized (getSingletonMutex()) {
//先從快取中獲取
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
//從FactoryBean中獲取bean
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
// 如果在上面的 getObject() 呼叫期間尚未放置,則僅進行後處理和儲存(例如,由於自定義 getBean 呼叫觸發的迴圈引用處理)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
// 暫時返回非後處理物件,暫不儲存..
return object;
}
beforeSingletonCreation(beanName);
try {
//呼叫ObjectFactory的後置處理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
// 從 FactoryBean 獲取物件
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
// 後置處理從 FactoryBean 獲取的物件
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
跟進doGetObjectFromFactoryBean()
方法,這個方法就更簡單了,就是呼叫工廠bean的getObject()
方法返回bean。
/**
* Obtain an object to expose from the given FactoryBean.
*
* 從給定的 FactoryBean 中獲取要公開的物件。
*
* @param factory the FactoryBean instance
* @param beanName the name of the bean
* @return the object obtained from the FactoryBean
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
//需要許可權校驗
if (System.getSecurityManager() != null) {
// 省略部分程式碼...
}
else {
//直接呼叫factory.getObject()方法
object = factory.getObject();
}
}
catch (Throwable ex) {
// 省略部分異常處理...
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
// 不要為尚未完全初始化的 FactoryBean 接受 null 值:許多 FactoryBean 只返回 null。
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
到這裡,圖片上的第三部分過完了。接下來是第四步。
真正進入建立Bean的流程
經過前面這麼多鋪墊,才真正走到了建立Bean的地方。這裡會比較複雜且囉嗦,需要點耐心看完。
這部分程式碼如下,可以跟著註釋看下這段程式碼。這裡先對原型型別的迴圈依賴進行校驗,原型bean出現迴圈依賴直接拋異常。然後回去父容器裡獲取,緊接著又處理了被@DependsOn
註解標註的依賴,然後再進行bean的建立。
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 在快取中獲取不到這個Bean
// 原型下的迴圈依賴直接報錯
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
// 核心要義,找不到我們就從父容器中再找一次
// 我們簡單的示例是不會有父容器存在的,這一塊可以理解為遞迴到父容器中查詢,跟在當前容器查詢邏輯是類似的
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 從父容器獲取,根據不同的引數呼叫不同的方法
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
// 如果不僅僅是為了型別推斷,也就是代表我們要對進行例項化
// 那麼就將bean標記為正在建立中,其實就是將這個beanName放入到alreadyCreated這個set集合中
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 為什麼這裡需要再獲取一次,因為經過之前的操作,RootBeanDefinition 可能已經發生了改變,
// 其中的 stale 屬性可能已經設為 true,這時需要去容器裡重新獲取,而不是直接從快取中返回
// 例如上面的 markBeanAsCreated() 方法就會修改 stale 屬性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 檢查合併後的bd是否是abstract,這個檢查現在已經沒有作用了,必定會通過
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// @DependsOn註解標註的當前這個Bean所依賴的bean名稱的集合,
// 就是說在建立當前這個Bean前,必須要先將其依賴的Bean先完成建立
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// 遍歷所有申明的依賴
for (String dep : dependsOn) {
// 如果這個bean所依賴的bean又依賴了當前這個bean,出現了迴圈依賴,直接報錯
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 註冊bean跟其依賴的依賴關係,key為依賴,value為依賴所從屬的bean
registerDependentBean(dep, beanName);
try {
// 先建立其依賴的Bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.建立bean例項
// 我們目前只分析單例的建立,單例看懂了,原型自然就懂了
if (mbd.isSingleton()) {
// 這裡再次呼叫了 getSingleton() 方法,
// 這裡跟方法開頭呼叫的 getSingleton() 的區別在於,
// 這個方法多傳入了一個 ObjectFactory 型別的引數,
// 這個 ObjectFactory 會返回一個 Bean
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.
// 從單例快取中顯式刪除例項:它可能已被建立過程提前地放在那裡,以允許迴圈引用解析。
// 還要刪除任何接收到對 bean 的臨時引用的 bean。
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
// 省略部分異常處理...
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
其實去掉部分校驗,去掉部分複雜場景下才會有的邏輯,核心程式碼就是getSingleton(String beanName, ObjectFactory<?> singletonFactory)
方法,這個方法是不是有點眼熟,getSingleton()
有三個同名的過載方法。前兩個上面已經見過,這裡是第三個。
仔細看這段程式碼,singletonFactory
部分傳入的是個lambada
表示式,裡面是正常建立bean的createBean()
方法。
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 省略部分異常處理...
}
});
結合getSingleton()
方法檢視,該方法處理一些前置判斷和後置處理後,核心的程式碼就是singletonFactory.getObject()
方法,這裡執行的就是上面傳入的lambada
表示式,也就是會執行到createBean(beanName, mbd, args)
方法。createBean(beanName, mbd, args)
又是一個很曲折的方法,簡直是曲折他媽給曲折開門,曲折到家了。所以我打算下一篇Spring Ioc原始碼分析系列--Bean例項化過程(二)說。在建立完成後,會把bean放入單例快取singletonObjects
中。
/**
* Return the (raw) singleton object registered under the given name,
* creating and registering a new one if none registered yet.
*
* 返回以給定名稱註冊的(原始)單例物件,如果尚未註冊,則建立並註冊一個新物件。
*
* @param beanName the name of the bean
* @param singletonFactory the ObjectFactory to lazily create the singleton
* with, if necessary
* @return the registered singleton object
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 從單例池中獲取,第一次進來這個地方肯定獲取不到
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 工廠已經在銷燬階段了,這個時候還在建立Bean的話,就直接丟擲異常
if (this.singletonsCurrentlyInDestruction) {
// 省略部分日誌及異常處理...
}
// 在單例建立前,記錄一下正在建立的單例的名稱,
// 就是把beanName放入到singletonsCurrentlyInCreation這個set集合中去
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 這裡呼叫了singletonFactory的getObject方法,
// 對應的實現就是在doGetBean中的那一段lambda表示式
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) {
// 省略部分異常處理...
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 在單例完成建立後,將beanName從singletonsCurrentlyInCreation中移除
// 標誌著這個單例已經完成了建立
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 新增到單例池中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
進行型別轉換
這裡已經分析到了截圖的第五部分,由於第四部分真正建立bean的部分放到了下一篇Spring Ioc原始碼分析系列--Bean例項化過程(二)去分析,所以到這裡的時候,我們已經完成了bean的建立,這個時候,如果方法傳入的requiredType
不為空,那麼就需要進行型別轉換,如果轉換失敗,則丟擲異常。轉換成功則返回當前完成型別轉換的convertedBean
。至此,建立bean的流程結束,已經可以返回一個可使用的bean,是不是還是挺簡單的。流程清晰。關於Spring的型別轉換和校驗也可以分一篇文章去分析TypeConverter
和ConversionService
在Spring體系裡的前世今生,這裡就不再贅述了。
// Check if required type matches the type of the actual bean instance.
// 檢查所需型別是否與實際 bean 例項的型別匹配。
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
回撥SmartInitializingSingleton實現類
到這裡完成單例bean的建立了,那就到了最後一步了,回撥SmartInitializingSingleton#afterSingletonsInstantiated()
方法,這裡沒啥好說的,就是第二個迴圈乾的事。遍歷所有的beanNames
,然後完成回撥。
這裡的回撥有很多實現類,比較經典的是EventListenerMethodProcessor
類,該類會在這一步完成了對已經建立好的Bean的解析,會判斷其方法上是否有 @EventListener
註解,會將這個註解標註的方法通過EventListenerFactory
轉換成一個事件監聽器並新增到監聽器的集合中。
總結
這篇文章還是按照之前的行文思路,分析得比較扁平,每個方法都沒有特別過分的深入去講解,因為那樣太深了很多人受不了,容易翻車。
回顧一下本文的思路,先是順著上文的入口,開始分析bean的建立。首先是獲取BeanDefinition,然後是呼叫getBean(beanName)
方法進行物件的例項化。該方法由一個截圖,分為了五部分去解析。分為了哪五部分還記得嗎?忘記了?那不怪你,我瞎幾把寫的。
第四步建立bean的部分我留到了下一篇去分析,這樣思路應該也比較清晰,不會那麼容易翻車。
如果有人看到這裡,那在這裡老話重提。與君共勉,路漫漫其修遠兮,吾將上下而求索。