Spring原始碼深度解析總結(6)—— 配置檔案的讀取和Bean的載入(四)
經過前面的分析,我們終於結束了對XML配置檔案的解析,接下來將會面對更大的挑戰,就是對bean載入的探索。bean載入的功能的實現遠比bean的解析複雜的多,同樣,我們還是以最簡單的示例為基礎,對於bean的功能,在Spring中的呼叫方式為:
MyTestBean bean = (MyTestBean) bf.getBean("myTestBean");
這句程式碼實現了什麼樣的功能呢,我們可以先快速體驗一下Spring中程式碼是如何實現的。
package org.springframework.beans.factory.support; public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { //提取對應的beanName final String beanName = transformedBeanName(name); Object bean; //檢查快取中或者例項工廠中是否有對應的例項 //為什麼首先會出現這段程式碼呢,因為在建立單例bean的時候會存在依賴注入的情況,而在建立依賴的時候為了避免迴圈依賴 //Spring建立bean的原則是不等bean建立完成就會將建立bean的ObjectFactory提早曝光,也就是將ObjectFactory加入到快取中, //一旦下個bean建立時候需要依賴上個bean則直接使用 //嘗試從快取獲取或從singletonFactories中的ObjectFactory中獲取 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } //返回對應的例項,有時候存在諸如BeanFactory的情況並不是直接返回例項本身而是返回指定方法返回的例項 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //只有在單例情況下才會嘗試解決依賴迴圈,原型模式情況下,如果存在A中有B的屬性,B中有A的屬性,那麼當依賴注入的時候 //就會產生當A還未建立完的時候因為對於B的建立再次返回建立A,造成迴圈依賴,也就是isPrototypeCurrentlyInCreation(beanName) //為true if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { //如果beanDefinitionMap中也就是在所有已經載入的類中不包括beanName則嘗試從parentBeanFactory中檢測 String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { return (T) parentBeanFactory.getBean(nameToLookup, args); } else { return parentBeanFactory.getBean(nameToLookup, requiredType); } } //如果不是僅僅做型別檢查則是建立bean,這裡要進行記錄 if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { //將儲存XML配置檔案的GenericBeanDefinition轉換為RootBeanDefinition, //如果指定BeanName是子Bean的話同時會合並父類的相關屬性 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // 若存在依賴則需要遞迴例項化依賴的bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } //快取依賴呼叫 registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } //例項化依賴的bean後便可以例項化mbd本身了 //singleton模式的建立 if (mbd.isSingleton()) { 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. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //prototype模式的建立 else if (mbd.isPrototype()) { Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { //指定的scope上例項化bean 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) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } //檢查需要的型別是否符合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.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; } }
第一次看到這段程式碼的讀者可能和我的感覺是一樣的,那就是長,非常的長,而且裡面涉及的邏輯也非常的多,所以在分析這段程式碼之前我們還是先捋一捋大致的步驟,以便於後面能順利的理解:
(1)轉換對應的beanName
或許很多人不理解轉換對應beanName是什麼意思,傳入的引數name不就是beanName嗎?其實不一定,這裡傳入的name有可能是別名,也可能是FactoryBean,所以需要進行一系列的解析,這些解析內容包括如下內容
i.去除FactoryBean的修飾符,也就是如果name="&aa",那麼會首先去除&,而是name="aa"。
ii.取指定alias所表示的最終beanName,例如別名A指向名稱為B的bean則返回B,若別名A指向別名B,別名B又指向名稱為C的bean則返回C
(2)嘗試從快取中載入單例
單例在Spring的同一個容器內只會被建立一次,後續再獲取bean,就直接從單例快取中獲取了。當然這裡也只是嘗試載入,首先嚐試從快取中載入,如果載入不成功則再次嘗試從singletonFactories中載入。因為在建立單例bean的時候會存在依賴注入的情況,而在建立依賴的時候為了避免迴圈依賴,在Spring中建立bean的原則是不等bean建立完成就會建立bean的ObjectFactory提早曝光加入到快取中,一旦下一個bean建立時候需要依賴上一個bean則直使用ObjectFactory
(3)bean的例項化
如果從快取中得到了bean的原始狀態,則需要對bean進行例項化。這裡有必要強調一下,快取中記錄的只是最原始的bean狀態,並不一定是我們最終想要的bean。舉個例子,加入我們需要對工廠bean進行處理,那麼這裡得到的其實是工廠bean的初始狀態,但是我們真正需要的是工廠bean中定義的factory-method方法返回的bean,而getObjectForBeanInstance就是完成這個工作的。
(4)原型模式的依賴檢查
只有在單例情況下才會嘗試解決迴圈依賴,如果存在A中有B屬性,B中有A屬性,那麼當依賴注入的時候,就會產生當A還未建立完的時候因為對於B的建立再次返回建立A,造成迴圈依賴,也就是情況:isPrototypeCurrentInCreation(beanName)==true。
(5)檢測parentBeanFactory
從程式碼上看,如果快取沒有資料的話直接轉到父類工廠上去載入了,這是為什麼呢?
可能我們忽略了一個很重要的判斷條件:parentBeanFactory != null && !containsBeanDefinition(beanName),parentBean如果為空,則一切免談,這個顯而易見。但是containBeanDefinition(beanName)就比較重要了,它是檢測如果當前載入的XML配置檔案中不包含beanName所對應的配置,就只能到parentBeanFactory去嘗試下了,然後再去遞迴的呼叫getBean方法。
(6)將儲存XML配置檔案的GenericBeanDefinition轉換為RootBeanDefinition。
因為從XML配置檔案中讀取到的Bean資訊是儲存在GenericBeanDefinition中的,但是所有的Bean後續處理都是針對於RootBeanDefinition的,所以這裡需要進行一個轉換,轉換的同時如果父類bean不為空的話,則會一併合併父類的屬性。
(7)尋找依賴
因為bean的初始化過程中很可能會用到某些屬性,而某些屬性很可能是動態配置的,並且配置成依賴於其他的bean,那麼這個時候就有必要先載入依賴的bean,所以在Spring的載入順序中,在初始化某一個bean的時候首先會初始化這個bean所對應的依賴。
(8)針對不同的scope進行bean的建立
我們都知道,在Spring中存在著不同的scope,其中預設的是singleton,但是還有些其他的配置諸如prototype、request、session之類的。在這個步驟中,Spring會根據不同的配置進行不同的初始化策略。
(9)型別轉換
程式到這裡返回bean後已經基本結束了,通常對該方法的呼叫引數requiredType是為空的,但是可能會存在這樣的情況,返回的bean其實是個String,但是requiredType卻傳入Integer型別,那麼這個時候本步驟就會起作用了,他的功能是將返回的bean轉換為requiredType所指定的型別。
經過上面的步驟後bean的載入就結束了,這個時候就可以返回我們所需要的bean了,在細化分析各個步驟提供的功能前我們有必要先了解下FactoryBean的用法。
FactoryBean的使用
一般情況下,Spring通過反射機制利用bean的class屬性指定實現類來例項化bean。在某些情況下,例項化bean過程比較複雜,如果按照傳統的方式,則需要在<bean>中提供大量的配置資訊,配置方式的靈活性是受限的,這時採用編碼的方式可能會得到一個簡單的方案。Spring為此提供了一個org.Springframework.bean.factory.FactoryBean的工程類介面,使用者可以通過實現介面定製例項化bean的邏輯。
FactoryBean介面對於Spring框架來說佔有重要的地位,Spring自身就提供了70多個FactoryBean的實現。它們隱藏了例項化一些複雜bean的細節,給上層應用帶來了便利。從Spring3.0開始,FactoryBean開始支援泛型,即介面宣告改為FactoryBean<T>的形式:
package org.springframework.beans.factory;
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton() {
return true;
}
}
在該介面中還定義了以下3個方法
T getObject() throws Exception :返回由FactoryBean建立的bean例項,如果isSingleton()返回true,則該例項會放到Spring容器中單例項快取池中。
boolean isSingleton() : 返回由FactoryBean建立的例項的作用域是singleton還是prototype。
Class<?> getObjectType() : 返回FactoryBean建立的bean型別
當配置檔案中<bean>的class屬性配置的實現類是FactoryBean時,通過getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getBean()方法所返回的物件,相當於FactoryBean#getObject()代理了getBean()方法。例如:如果使用傳統方式配置下面Car的<bean>時,Car的每個屬性分別對應一個<property>元素標籤。
public class Car{
private int maxSpeed;
private String brand;
private double price;
//get set方法
}
如果用FactoryBean的方式實現就會靈活一些,下例通過逗號分割符的方式一次性地為Car的所有屬性指定配置值:
public class CarFactoryBean implements FactoryBean<Car>{
private String carInfo;
public Car getObject() throws Exception{
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0]);
car.setMaxSpeed(Integer.valueOf(infos[1]));
car.setPrice(Double.valueOf(infos[2]));
return car;
}
public Class<Car> getObjectType(){
return Car.class;
}
public boolean isSingleton(){
return false;
}
public String getCarInfo(){
return this.carInfo;
}
public void setCarInfo(Stirng carInfo){
this.carInfo = carInfo;
}
}
有了這個CarFactoryBean後,就可以在配置檔案中使用下面這種自定義的配置方式配置CarBean了:
<bean id="car" class="com.test.factorybean.CarFactoryBean" carInfo="超級跑車,400,100000" />
當呼叫getBean("car")時,Spring通過反射機制發現CarBeanFactory實現了FactoryBean的介面,這時Spring容器就呼叫介面方法CarFactoryBean#getObject()方法返回。如果希望獲取CarFactoryBean的例項,則需要在使用getBean(beanName)方法時在beanName前顯示的加上"&"字首,例如getBean("&car")。
快取中獲取單例bean
介紹過FactoryBean的用法後,我們就可以瞭解bean載入的過程了。前面已經提到過,單例在Spring的同一個容器內只會被建立一次,後續再獲取bean直接從單例快取中獲取,當然這裡也只是嘗試載入,首先嚐試從快取中載入,然後再次嘗試從singletonFactories中載入。因為在建立單例bean的時候會存在依賴注入的情況,而在建立依賴的時候為了避免迴圈依賴,Spring建立bean的原則是不等bean建立完成就會將建立bean的ObjectFactory提早曝光加入到快取中,一旦下一個bean建立時需要依賴上個bean,則直接使用ObjectFactory。
package org.springframework.beans.factory.support;
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
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) {
//如果為空且allowEarlyReference為true則獲取singletonFactories中的例項
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//呼叫預先設定的getObject方法
singletonObject = singletonFactory.getObject();
//記錄在快取earlySingletonObjects中
this.earlySingletonObjects.put(beanName, singletonObject);
//在快取singletonFactories中刪除該例項
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
}
這個方法因為涉及迴圈依賴的檢測,以及涉及很多變數的記錄存取,所以讓人摸不著頭腦。這個方法首先嚐試從singletonObjects裡面獲取例項,如果獲取不到再從earlySingletonObjects裡面獲取,如果還獲取不到,再嘗試從singletonFactories裡面獲取beanName對應的ObjectFactory,然後呼叫這個ObjectFactory的getObject來建立bean,並放到earlyReferenceObjects裡面去,並且從singletonFactories裡面remove掉ObjectFactory,而對於後續的所有記憶體操作都只為了迴圈依賴檢測時候使用,也就是allowEarlyReference為true的情況下使用。
這裡涉及用於儲存bean的不同的map,可能會讓我們感到崩潰,簡單的解析一下:
singletonObjects:用於儲存BeanName和建立bean例項之間的關係,bean name --> bean instance
singletonFactories:用於儲存BeanName和建立bean的工廠之間的關係,bean name --> ObjectFactory。與earlySingletonObjects互斥
earlySingletonObjects:也是儲存BeanName和建立bean例項之間的關係,與singletonObjects不同的地方在於,當一個單例bean被放到這裡面後,那麼當bean還在建立過程中就可以通過getBean獲得了,其目的是用來檢測迴圈引用。與singletonFactories互斥
registeredSingletons:用來儲存當前所有已註冊的bean
從bean的例項獲取物件
在getBean方法中,getObjefctForBeanInstance是個高頻率使用的方法,無論是從快取中獲得bean還是根據不同的scope策略載入bean。總之,我們得到bean的例項後要做的第一步就是呼叫這個方法來檢測一下正確性,其實就是用於檢測當前bean是否是FactoryBean型別的bean,如果是,那麼需要呼叫該bean對應的FactoryBean例項中的getObject方法作為返回值
無論是從快取中獲取到的bean還是通過不同的scope策略載入的bean都只是最原始的bean狀態,並不一定是我們最終想要的bean。舉個例子,假如我們需要對工廠bean進行處理,那麼這裡得到的其實是工廠bean的初始狀態,但是我們真正需要的是工廠bean中定義的factory-method方法返回的bean,而getObjectForBeanInstance方法就是幹這個工作的。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//如果指定的name是工廠相關(以&為字首)
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//如果beanInstance不是FactoryBean型別,則丟擲異常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
//現在我們有了一個bean例項,這個例項可能是FactoryBean也可能是正常的bean,
//如果是FactoryBean我們使用建立例項,但是如果使用者想要直接獲取工廠例項而不是工廠getObject所對應的例項
//那麼傳入的name應該加字首&
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
//剩下的就是FactoryBean且是需要返回FactoryBean的getObject方法所對應的例項
Object object = null;
if (mbd == null) {
//嘗試從快取中載入bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
//containsBeanDefinition檢測beanDefinitionMap中也就是所有已經載入的類中檢測是否定義benaName
if (mbd == null && containsBeanDefinition(beanName)) {
//將儲存XML配置檔案的GenericBeanDefinition轉換為RootBeanDefintion,如果指定BeanName是子Bean的話同時合併父類的相關屬性
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否是使用者定義的而不是應用程式本身定義的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
從上面的程式碼來看,其實這個方法並沒有什麼重要的資訊,大多是些輔助程式碼以及一些功能性的判斷,而真正核心的程式碼卻委託給了getObjectFromFactoryBean,我們來看看getObjectForBeanInstance所做的工作
(1)對FactoryBean正確性的驗證
(2)對非FactoryBean不做任何處理
(3)對bean進行轉換
(4)將從Factory中解析bean的工作委託給getObjecFromFactoryBean
我們下面來看看getObjectFromFactoryBean方法的內容
package org.springframework.beans.factory.support;
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//如果是單例模式
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
//嘗試從快取中獲取BeanName對應的例項
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
//判斷是否在獲取object期間已經在快取中儲存了BeanName對應的例項
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 {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
//將BeanName和對應的例項加入快取
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
//其他模式則直接建立即可
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
}
很遺憾,在這個程式碼中我們還是沒有看到想要看到的程式碼,在這個方法裡只做了兩件事,一件是保證單例模式的例項是唯一的,另一件就是對bean進行後處理。下面我們看一下後處理程式碼
package org.springframework.beans.factory.support;
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
}
對於後處理器的使用我們還未過多接觸,後續文章會使用大量篇幅介紹,這裡,我們只需要瞭解在Spring獲取bean的規則中有這樣一條:儘可能保證所有bean初始化後都會呼叫註冊的BeanPostProcessor的postProcessAfterInitialization方法進行處理,在實際的開發中大可以針對此特性設計自己的業務邏輯
在doGetObjectFromFactoryBean方法中我們終於看到了我們想要看到的方法,也就是factory.getObject(),我們下面來看一下
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
//許可權驗證
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//直接呼叫getObject方法建立例項
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
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;
}
上面的程式碼沒有什麼難懂的地方,這裡就不再贅述了。
獲取單例
現在讓我們回到最開始的doGetBean方法中去,截止到目前為止,我們已經分析了當快取中存在BeanName對應的bean例項的情況,下面我們要討論的就是快取中不存在BeanName對應的bean例項的情況。在這種情況下我們首先要判斷是否存在原型模式下迴圈依賴的問題,如果不存在且當前配置的檔案中不存在BeanName的配置,可以嘗試去父工廠去查詢。如果都沒有的話則首先例項化依賴的bean,然後開始建立beanName對應的bean例項,使用的是getSingleton方法,這個方法和之前獲取快取中的bean例項的getSingleton方法的過載方法。下面我們來看一看程式碼:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
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 {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
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.
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) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
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.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
上述程式碼其實是使用了回撥方法,使得程式可以在單例中建立的前後做一些準備級處理操作,而真正獲取單例bean的方法其實並不是在此方法中實現的,其實現邏輯是在ObjectFactory型別的例項singletonFactory的getObject方法中實現的。而這些準備及處理操作包括如下內容。
(1)檢查快取是否已經載入過
(2)若沒有載入,則記錄beanName的正在載入狀態
(3)載入單例前記錄載入裝態
可能你會覺得beforeSingletonCreation方法是個空實現,裡面沒有任何邏輯,但其實不是,這個函式中做了一個很重要的操作:記錄載入狀態,也就是通過this.singletonCurrentlyInCreation.add(beanName)將正要建立的bean記錄在快取中,這樣便可以對迴圈依賴進行檢測,下面是程式碼:
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
(4)通過呼叫引數傳入的ObjectFactory的個體Object方法例項化bean
(5)載入單例後的處理方法呼叫。同步驟(3)記錄載入狀態相似,當bean載入結束後需要移除快取中對該bean的正在載入狀態的記錄。下面是程式碼:
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
(6)將結果記錄至快取並刪除載入bean過程中所記錄的各種輔助狀態。下面是程式碼:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
(7)返回結果處理。
雖然我們已經從外部瞭解了載入bean的邏輯結構,但現在我們還並沒有開始對bean載入功能的探索,之前提到過,bean的載入邏輯其實是在傳入的ObjectFactory型別的singletonFactory中定義的,我們反推引數的獲取,得到如下程式碼
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
ObjectFactory的核心部分其實只是呼叫了createBean的方法,所以我們還需要到createBean方法中追尋真理
準備建立bean
我們不可能指望在一個函式中完成一個複雜的邏輯,而且我們跟蹤了這麼多的Spring程式碼,經歷了這麼多的函式,或多或少也發現了一些規律:一個真正幹活的函式其實都是以do開頭的,比如doGetObjectFromFactoryBean;而給我們錯覺的函式,比如getObjectFromFactoryBean其實只是從全域性角度去做些統籌的工作。這個規則對於createBean也不例外,那麼讓我們看看在createBean函式中都做了哪些準備工作。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
//鎖定class,根據設定的class屬性或者className解析class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
//驗證及準備覆蓋的方法
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
//給BeanPostProcessors一個機會來返回代理來代替真正的例項
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
//建立bean例項
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
從程式碼我們可以總結出函式完成的具體步驟及功能
(1)根據設定的class屬性或者根據className來解析Class
(2)對override屬性進行標記和驗證。我們知道在Spring中是沒有override-method這樣的配置的,但是Spring配置中是存在lookup-method和replace-method的,而這兩個配置的載入其實就是將配置統一存放在BeanDefinition中的methodOverrides屬性裡,而這個函式的操作 就是針對於這兩個配置的。
(3)應用初始化前的後處理器,解析bean是否存在初始化錢的短路操作
(4)建立bean
我們首先看下對override屬性標記及驗證的邏輯實現的程式碼:
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
//判斷是否overrideMethods中是否存在需要覆蓋的方法
if (hasMethodOverrides()) {
Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
//同步全域性變數
synchronized (overrides) {
for (MethodOverride mo : overrides) {
prepareMethodOverride(mo);
}
}
}
}
//真正實現覆蓋方法的方法
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
//獲取對應類中對應方法名的個數
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
else if (count == 1) {
//標記MethodOverrides暫未被覆蓋,避免參數型別檢查的開銷
mo.setOverloaded(false);
}
}
通過上面兩個函式的程式碼我們可以很清楚的看到Spring對於lookup-method和replace-method這兩個配置的處理過程。前面我們知道,這兩個配置屬性是統一存放在了BeanDefinition的methodOverrides屬性裡,這兩個功能的實現原理其實就是在bean例項化的時候如果檢測到存在methodOverrides屬性,會動態的為當前bean生成代理並使用對應的攔截器為bean做增強處理,相關邏輯實現在bean的例項化部分詳細介紹。
但是,這裡要提到的一點是,對於方法的匹配來講,如果一個類中存在若干個過載方法,那麼,在函式呼叫及增強的時候還需要根據引數型別進行匹配,來最終確認當前呼叫的到底是哪個函式。但是,Spring將一部分匹配工作在這裡完成了,如果當前類中的方法只有一個,那麼就設定過載該方法沒有被過載,這樣在後續呼叫的時候便可以直接使用找到的方法,而不需要進行方法的引數匹配驗證了,而且還可以對方法的存在性進行驗證,正可謂一箭雙鵰。
在處理完overrideMethods屬性後,我們可以看到Spring的程式碼中使用了這樣的一個方法resolveBeforeInstantiation(beanName, mbd)對BeanDefinition中的屬性做些前置處理。當然,無論其中是否有相應的邏輯實現我們都可以理解,因為真正邏輯實現前後留有處理函式也是可擴充套件的一種體現,但是,這並不是最重要的,在函式中還提供了一個短路判斷,這才是最為關鍵的部分。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
當經過前置處理後返回的結果如果不為空,那麼會直接略過後續的Bean的建立而直接返回結果。這一特性雖然很容易被忽略,但是卻起著至關重要的作用,我們熟知的AOP功能就是基於這裡判斷的。下面我們來看一下前置處理方法的程式碼:
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
此方法中最吸引我們的無疑是兩個方法:applyBeanPostProcessorsBeforeInstantiation以及applyBeanPostProcessorsAfterInstantiation。兩個方法實現的非常簡單,無非是對後處理器中的所有InstantiationAwareBeanPostProcess型別的後處理器進行postProcessBeforeInstantiation方法和BeanPostProcess的postProcessAfterInitialization方法的呼叫
(一)例項化前後處理器的呼叫
bean的例項化前呼叫,也就是將AbstractBeanDefinition轉化為BeanWrapper前的處理。給子類一個修改BeanDefinition的機會,也就是說當程式經過這個方法後,bean可能已經不是我們認為的bena了,而是或許成為一個經過處理的代理bean,可能是通過cglib生成的,也可能是通過其他技術生成的。這個在後面會詳細介紹,我們只需要知道,在bean的例項化前會呼叫後處理器的方法進行處理。下面是程式碼:
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
(二)例項化後的後處理應用
在講解從快取中獲取單例bean的時候就提到過,Spring中的規則是在bean的初始化後儘可能保證將註冊的後處理器的postProcessAfterInitialization方法應用到該bean中,因為如果返回的bean不為空,那麼便不會再次經歷普通的bean的建立過程,所以只能在這裡應用後處理器的postProcessAfterInitialization方法。下面是程式碼:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
在經歷了resolveBeforeInstantiation方法後,程式有兩個選擇,如果建立了代理或者說重寫了InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法並在方法postProcessBeforeInstantiation中改變了bean,則直接返回就可以了,否則需要進行常規bean的建立,而常規bean的建立就是在doCreateBean中完成的
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//根據指定bean使用對應的策略建立新的例項,如:工廠方法、建構函式自動注入、簡單初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
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");
}
//為避免後期迴圈依賴,可以在bean初始化完成前將建立例項的ObjectFactory加入工廠
//對bean的再一次依賴引用,主要應用SmartInstantiationAwareBeanPostProcessor,其中我們熟知的AOP
//就是在這裡將advice動態織入到bean中,若沒有則直接返回bean,不做任何處理
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//對bean進行填充,將各個屬性值注入,其中可能存在依賴於其他bean的屬性,則會遞迴初始依賴bean
populateBean(beanName, mbd, instanceWrapper);
//呼叫初始化方法,比如init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
//earlySingletonReference只有在檢測到有迴圈依賴的情況下才會不為空
if (earlySingletonReference != null) {
//如果exposedObject沒有在初始化方法中被改變,也就是沒有被增強
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
//檢測依賴
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
//因為bean建立後其所依賴的bean一定是已經建立的,actualDependentBeans不為空則表示當前bean建立後其依賴的bean卻沒有
//全部建立完,所以說存在迴圈依賴
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
//根據scope註冊bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
儘管日誌與異常的內容非常重要,但是在閱讀原始碼的時候似乎大部分人都會直接忽略掉。在此不深入討論日誌及異常的設計,我們看看整個函式的概要思路。
(1)如果是單例則需要首先清除快取
(2)例項化bean,將BeanDefinition轉換為BeanWrapper :轉換是一個複雜的過程,但是我們可以嘗試概括大致的功能,如下所示
i.如果存在工廠方法則使用工廠方法進行初始化
ii.一個類有多個建構函式,每個建構函式都有不同的的引數,所以需要根據引數鎖定建構函式並進行初始化
iii.如果既不存在工廠方法也不存在帶有引數的構造方法,則使用預設的建構函式進行bean的例項化
(3)MergedBeanDefinitionPostProcessor的應用:bean合併後的處理,Autowired註解正是通過此方法實現諸如型別的預解析
(4)依賴處理:在Spring中會有迴圈依賴的情況,例如,當A中含有B屬性,而B中又含有A的屬性時就會構成一個迴圈依賴,此時如果A和B都是單例的,那麼Spring中的處理方式就是當建立B時,涉及自動注入A的步驟時,並不是直接去再次建立A,而是通過放在快取中的ObjectFactory來建立例項,這樣就解決了迴圈依賴的問題。對於迴圈依賴的講解可以看一下這裡
(5)屬性填充:將所有屬性填充至bean的例項中
(6)迴圈依賴檢查:之前提到過,在Spring中解決迴圈依賴只對單例有效,而對於prototype的bean,Spring沒有好的解決辦法,唯一要做的就是丟擲異常。在這個步驟龍裡面會檢測已經載入的bean是否已經出現了依賴迴圈,並判斷是否需要丟擲異常。
(7)註冊DisposableBean。
(8)完成建立並返回。
可以看到上面的步驟非常的繁瑣,每一步都使用了大量的程式碼來完成其功能,最複雜也是最難以理解的當屬迴圈依賴的處理,在真正進入doCreateBean之前,我建議大家有必要先了解一下迴圈依賴。
建立bean的例項
當我們瞭解了迴圈依賴以後就可以深入分析建立bean的每個步驟了,首先我們從createBeanInstance開始
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
//解析class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//bean的方法不為public,且不允許訪問非public方法則丟擲異常
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());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果工廠方法不為空,則採用工廠方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same 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);
}
}
//需要根據引數解析建構函式
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//建構函式自動注入
return autowireConstructor(beanName, mbd, ctors, args);
}
//使用預設建構函式構造
return instantiateBean(beanName, mbd);
}
雖然程式碼中例項化的細節非常複雜,但是在createBeanInstance方法中我們還是可以清晰地看到例項化的邏輯。
(1)如果在RootBeanDefinition中存在factoryMethodName屬性,或者說在配置檔案中配置了factory-method,那麼Spring會嘗試使用instantiateUsingFactoryMethod(beanName, mbd, args)方法根據RootBeanDefinition中配置生成bean的例項
(2)解析建構函式並進行建構函式的例項化。因為一個bean對應的類中可能會有多少個建構函式,而每個建構函式的引數不同,Spring在根據引數及型別去最終判斷會使用哪個建構函式進行例項化。但是,判斷的過程是個比較消耗效能的步驟,所以採用快取機制,如果已經解析過則不需要重複解析而是直接從RootBeanDefinition中的屬性resolvedConstructorOrFactoryMethod快取的值去取,否則需要再次解析,並將解析的結果新增至RootBeanDefinition中的屬性resolvedConstructorOrFactoryMethod中。
1、autowireConstructor
對於例項的建立Spring中分成了兩種情況,一種是通用的例項化,另一種是帶有引數的例項化。帶有引數的例項化過程相當複雜,因為存在著不確定性,所以在判斷對應引數上做了大量工作。
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
//explicitArgs通過getBean方法傳入,如果getBean方法呼叫的時候指定方法引數那麼直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
//如果在getBean方法時候沒有指定則嘗試從配置檔案中解析
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
//從快取中獲取
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
//配置的建構函式引數
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
//如果快取中存在
if (argsToResolve != null) {
//解析引數型別,如給定方法的建構函式A(int, int)則通過此方法後就會把配置中的("1", "1")轉化為(1, 1)
//快取中的原始也可能是最終值
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
//沒有被快取
if (constructorToUse == null) {
// Need to resolve the constructor.
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
//提取配置檔案中的配置的建構函式引數
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
//用於承載解析後的建構函式引數
resolvedValues = new ConstructorArgumentValues();
//能解析到的引數個數
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// Ta