Spring 如何建立 bean 物件?

2021-10-21 10:33:14 字數 4130 閱讀 9782

前文「spring 如何從 ioc 容器中獲取物件?」從整體上分析了如何從 spring ioc 容器獲取乙個 bean 物件。該邏輯由 abstractbeanfactory#dogetbean 方法實現,主要流程如下:

本文進一步深入細節,主要分析如何建立 singleton(單例)型別的物件。

從流程圖可以看出,當獲取乙個 bean 物件時,spring 會首先嘗試從快取中獲取單例物件。

值得注意是的:

只有物件是單例的場景,即 scope 為 singleton 時才會快取物件。

這裡其實涉及到了所謂的「**快取」,為了更容易理解**快取,本文先研究這個 bean 物件是什麼時候放入快取的,後面再研究**快取。

既然能取,必然有地方把 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...