1. 程式人生 > >Spring原始碼深度解析總結(6)—— 配置檔案的讀取和Bean的載入(四)

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初始化後都會呼叫註冊的BeanPostProcessorpostProcessAfterInitialization方法進行處理,在實際的開發中大可以針對此特性設計自己的業務邏輯

在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型別的例項singletonFactorygetObject方法中實現的。而這些準備及處理操作包括如下內容。

(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方法和BeanPostProcesspostProcessAfterInitialization方法的呼叫

(一)例項化前後處理器的呼叫

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方法後,程式有兩個選擇,如果建立了代理或者說重寫了InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiation方法並在方法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