Spring GetBean流程

 第一節講解Spring啓動的時候說到,Spring內部先解析了全部的配置,加載全部的Bean定義後,再根據須要對Bean進行實例化和初始化。除開Spring本身主動新建的對象,第一次根據Bean定義加載對象的動做出如今AbstractApplicationContext的invokeBeanFactoryPostProcessors方法,該方法會在Spring容器中找出實現了BeanFactoryPostProcessor接口的bean列表並執行。根據以前介紹的內容,內部主要調用了AbstractBeanFactory的getBean方法,這節將對該方法進行講解。html

1、getBean

 在這以前,先介紹BeanFactory的層次結構,以下:緩存

file

涉及到的接口和實現類爲:ide

 AliasRegistry:別名管理接口,定義了別名管理的功能post

 SimpleAliasRegistry:AliasRegistry的默認實現,內部用一個ui

 ConcurrentHashMap:管理別名this

 SingletonBeanRegistry:單例實例管理接口,定義了單例管理的功能spa

 DefaultSingletonBeanRegistry:單例管理實現類,內部用Map維護着被實例化後的全部單例、單例工廠等相關信息。Map的鍵爲bean的惟一標識,Spring內部成爲raw name,通常等同於Bean定義中的id或者name或者別名等,具體規則能夠從上節BeanDefinition的加載查看,值爲相應的對象實例。這邊須要指出的一點是,對於bean定義中具備別名意義的字段,如必定狀況下的name以及alias字段,只存在於SimpleAliasRegistry維護的內部Map中,經過遞歸查詢的方式能夠從一個給定的別名查找到指定的id。prototype

 以下,DefaultSingletonBeanRegistry維護的Map中存在key爲testBean,value爲TestBean的對象,SimpleAliasRegistry維護的Map中存在Key爲testBeanAlias1,value爲testBean的記錄。當經過testBeanAlias1查找bean時,會先經過AliasRegistry查找到testBean,再從經過BeanRegistry查找到對應的Bean實例。線程

file

 FactoryBeanRegistrySupport:增長緩存FactoryBean實例功能,DefaultSingleBeanRegistry在生成單例後便再也不持有對應的FactoryBeandebug

 BeanFactory:定義了Bean容器的基本查詢接口,同時設定了以&前綴來區別工廠Bean,即若是beanName前面有&則返回對應Bean的工廠Bean對象而不是該Bean對象。

 HierarchicalBeanFactory:在BeanFactory接口上增長了父子層級關係,以實現雙親委託。

 ConfigurableBeanFactory:按照規矩,增長了修改功能的接口,同時增長了Scope特性,默認分爲single單例和prototype多例。

 AbstractBeanFactory:BeanFacoty的基本實現。

 AbstractBeanFactory的getBean方法內部調用了doGetBean,該方法提供了根據beanName獲取實例的具體實現,代碼以下(刪除了相關的註釋和空格):

protected <T> T doGetBean(
			final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
			throws BeansException {

		/*(1)*/
		final String beanName = transformedBeanName(name);
		Object bean;
		/*(2)*/
		Object sharedInstance = getSingleton(beanName);
		/*(3)*/
		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);
		}
		/*(4)*/
		else {
			/*(5)*/
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
			/*(6)*/
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				String nameToLookup = originalBeanName(name);
				if (args != null) {
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}
			/*(7)*/
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}
			try {
				/*(8)*/
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
				/*(9)*/
				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);
						}
					}
				}
				/*(10)*/
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							try {
								return createBean(beanName, mbd, args);
							}
							catch (BeansException ex) {
								destroySingleton(beanName);
								throw ex;
							}
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				/*(11)*/
				else if (mbd.isPrototype()) {
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
				/*(12)*/
				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, new ObjectFactory<Object>() {
							@Override
							public Object getObject() throws BeansException {
								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) {
				/*(13)*/
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}
		if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
			try {
				return getTypeConverter().convertIfNecessary(bean, requiredType);
			}
			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. name:要查找的bean名,能夠爲raw name,也能夠爲alias name或者factoryBean name,Spring內部會自行進行轉換。

  2. requiredType:要返回的對象類型

  3. args:對象實例化時須要用到的構造參數

  4. typeCheckOnly:該對象只是用來進行類型檢查,而不會真正的進行使用,能夠避免實例化和初始化對象

具體過程爲:

1.獲取raw name

 計算所給name對應的內部beanName,具體爲循環去除name前面的&,再根據以前的介紹的,若是傳入的是別名,會查找到對應的raw name

2.嘗試獲取bean實例

 使用上面得到的beanName,調用內部的getSingleton方法,獲取對應的對象實例,賦值給sharedInstance。getSingleton方法來自於DefaultSingletonBeanRegistry,即這步嘗試直接從內部維護的單例Map中獲取實例。這步能夠檢測到手工注入的singleton,如第一節提到的ApplicationContext對象,就是Spring本身手動註冊的。

3.bean實例已經存在

 若sharedInstance不爲空,且args參數爲空,說明該對象已經存在,不須要再進行實例化和初始化。因爲在(1)的時候對所傳的name去除了&,須要判斷返回的對象是否符合要求。這時候,會使用getObjectForBeanInstance方法,對sharedInstance和name進行判斷,返回對應的實例,該方法主要內容以下:

  1. 若name以&開頭,但sharedInstance沒有實現FactoryBean接口,則拋出異常

  2. 若sharedInstance沒有實現FactoryBean接口,或者name以&開頭,則直接將sharedInstance對象返回。即sharedInstace自己是從name對應的FactoryBean獲取的對象。

  3. 若前面2個條件都不符合,則sharedInstance自己實現了FactoryBean接口,name也是以&開頭,這時候會嘗試從FactoryBeanRegistrySupport中根據beanName(raw name)獲取已經實例化的對象。若對象爲空,即首次獲取,則將sharedInstace轉爲FactoryBean,並調用該工廠方法獲取對象。這裏涉及到FactoryBeanRegistrySupport的getObjectFromFactoryBean方法,該方法在使用FactoryBean得到對象後,會調用上下文中已有的BeanPostProcessor對象列表,逐個執行postProcessAfterInitialization方法,當遇處處理後的結果爲空,則直接返回,不然繼續遍歷執行,以下,出如今AbstractAutowireCapableBeanFactory中:

file

4.Bean實例不存在

 若是沒有找到beanName對應的實例,即不存在對應的單例實例,則轉入實例化該對象的流程,注意單例或者多例都須要實例化。

5.若是該beanName有對應的在初始化中的多例對象,則拋出異常。

 AbstractBeanFactory內部維護了一個ThreadLocal對象,用於維護當前線程正在初始化的多例對象。

6.啓用雙親委託機制

 若是存在父容器,且父容器存在該beanName的定義,則委託給父容器完成。

7.若是本次調用不單是爲了類型檢查,則標記該beanName在建立中

 AbstractBeanFactory內部維護了一個Set<String>集合alreadyCreated,用於存儲已經建立好或者正在建立的bean

8.獲取該beanName對應的BeanDefinition,包裝爲RootBeanDefinition返回。

 AbstractBeanFactory內部維護了一個Map<String, RootBeanDefinition>集合mergedBeanDefinitions,用於維護當前已經加載的各個bean定義bd。在加載該bean定義時,若是存在父定義pdb,則會將pdb包裝爲一個RootBeanDefinition,而後將當前的bd覆蓋掉父定義的內容,包括scope、lazyInit、dependsOn等屬性,達到繼承的效果。得到RootBeanDefinition後,若是最後的定義中scope爲空,則會默認賦值爲single。此外還有一個containingBd的概念,這個是相對於bd來講的,指的是包含bd的外部bean定義,主要用於inner bean的狀況。若是包含containingBd不爲空,且不是單例,可是bd爲單例,則bd的scope須要設置爲containingBd的值,直白點說就是包含被非單例bean包含的bean自己不能爲單例(這段有點繞,還沒找到實際的例子,直接按照代碼裏的直譯過來)。

9.處理依賴的bean

 獲取該bean依賴的bean列表dependsOn值,對每一個依賴的bean進行逐一操做,先檢查該bean是否存在循環依賴,若不存在循環依賴,則將依賴關係緩存起來,最後先實例化依賴的bean。其中檢查循環依賴很重要,若是沒有該步,最後實例化依賴的bean時會致使死循環。爲此AbstractBeanFacotry內部維護了兩個Map<String, Set<String>>屬性dependentBeanMap和dependenciesForBeanMap,分別用於緩存bean的依賴關係。前者表示bean從屬關係的緩存,緩存依賴於key所表示的bean的全部bean name,舉例來說,若是beanB的一個屬性是beanA,則beanA爲key是被依賴方,beanB則爲value是依賴方(從屬方)的一員;後者標識bean依賴關係的緩存,緩存key所表示的bean依賴的全部bean name,舉例來說,若是beanB的一個屬性是beanA,則beanB是key從屬方,beanA則是value被依賴方的一員。以下爲Spring檢查循環依賴的過程:

file

 其中beanName爲當前bean,dependentBeanName爲當前bean所依賴的bean。大體過程爲找出全部依賴beanName的bean列表transitiveDependency,遞歸判斷transitiveDependency是否也依賴dependentBeanNam,即若是 beanName依賴於 dependentBeanName ,並且 transitiveDependency依賴於 beanName, 若是transitiveDependency 依賴於dependentBeanName,即出現了環,則存在循環依賴。

10.若是該bean爲單例,則轉入初始化單例流程

 調用父類DefaultSingletonBeanRegistry的getSingleton模板方法,該模板方法會保證該單例只有被建立一次,建立完成後將對象緩存在內部。真正實例化和初始化的過程在createBean方法中,其中若是該bean實例化失敗,則會調用destroySingleton方法進行回收,這兩個方法在後面會進行重點講解。同第二步相似,獲取該對象後,會再調用getObjectForBeanInstance檢查FactoryBean。

11.若是該bean爲多例,則轉入初始化多例流程

 第(5)步講過,內部有一個ThreadLocal,保證多例在當前線程建立時是惟一的,重點方法也是createBean。須要注意的是,若是是多例,建立失敗是不會進行回收的。

12.若是該bean爲其餘scope,則轉入對應的初始化流程

 具體過程同(10)一致,只是調用的模板委託給了具體的Scope對象。

13.初始化失敗,則清理相關內容

 將該beanName從alreadyCreated移除,標識該beanName還未建立。

2、createBean

 createBean方法主要用於完成bean的實例化和初始化過程,該方法在AbstractFactory中爲抽象方法,具體實現是在AbstractAutowireCapableBeanFactory類中。以下爲核心操做:

file

1.resolveBeforeInstantiation

 建立對象前的代理口子,可以攔截建立過程,使用自定義的代理對象來替換Spring內部正常建立的對象,即上面判斷的,若是該方法返回對象不爲空,則直接使用返回的對象返回。實現上, 會逐一遍歷全部的BeanPostProcessor,找出InstantiationAwareBeanPostProcessor對象,並執行postProcessBeforeInstantiation方法,若返回結果不爲空,則直接使用該方法返回,以下:

file

 該方法主要用在AOP實現上,上節提到的CommonAnnotationBeanPostProcessor和PersistenceAnnotationBeanPostProcessor類雖然實現了該接口,可是postProcessBeforeInstantiation方法爲空實現。

 若該方法返回對象不爲空,則會逐一執行BeanPostProcessor列表的postProcessAfterInitialization方法,以完成回調。

2.doCreateBean

 該方法的主要過程以下,省略了提早暴露bean實例的部份內容。

file

 由上圖可知,該過程完成了bean的實例化和初始化以及調用各回調接口的過程。具體爲:

  1. 根據BeanDefinition實例化bean

 主要嘗試從各類方法進行實例化,包括:

a. 使用工廠方法進行實例化

b. 使用bean定義的構造方法或者可用的構造方法進行實例化

c. 使用默認的構造方法進行實例化

  1. 回調MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法

 以下,遍歷各個MergedBeanDefinitionPostProcessor實例,回調postProcessMergedBeanDefinition方法

file

3.初始化對象,填充各屬性

 執行初始化,實現屬性的依賴注入,在自動進行依賴注入前, 會先調用一個回調接口,以判斷是否須要自動依賴注入,以下:

file

 經過回調InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法來判斷。

 若須要進行依賴注入,則會根據依賴策略:根據autowireByName或者autowireByType,爲屬性字段找到符合定義的bean實例(會經過getBean方法調用)。在真正將值賦值給屬性前, 還會再次執行回調接口,以下,回調InstantiationAwareBeanPostProcessor的postProcessPropertyValues方法,這裏也能夠進行攔截。

file

 若前面都沒被攔截到,則會真正將bean值複製給對應的屬性,最終會經過反射設置field的accessable,而後將bean實例設置進去。

4.執行各回調接口

  1. 執行Aware接口,包括BeanNameAware、BeanClassLoaderAware和BeanFactoryAware

  2. 執行BeanPostProcessor的postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor類實現了該方法,用以回調@PostConstruct註解的方法,CommonAnnotationBeanPostProcessor繼承自該類,設置了initAnnotationType爲PostConstruct.class)方法

  3. 若是該Bean實現了InitializingBean接口,則調用afterPropertiesSet方法

  4. 若是設置了init-method,則執行init-method指定的方法

  5. 執行BeanPostProcessor的postProcessAfterInitialization方法

5.判斷是否有銷燬接口,並添加到列表中

 以下,爲處理過程,會先判斷當前bean定義不是多例,且須要進行銷燬回調,纔會進行處理。若是是單例,則直接將其添加到響應列表列表中進行緩存,存儲在內部維護的disposableBeans列表中;若是是其餘socpe,則將其委託給對應的Scope對象實現。

file

 這裏有幾個條件:

  1. 必須爲非prototy

  2. 該bean存在銷燬方法,知足一下條件之一便是

a. 該bean實現了DisposableBean接口

b. 該bean實現了AutoCloseable接口

c.該bean實現了Closeable接口

d.該bean定義的destory-method不爲空

e.該bean符合DestructionAwareBeanPostProcessor.requiresDestruction方法的過濾條件

 只要符合以上條件,就會新建一個DisposableBeanAdapter對象進行存儲,並在銷燬時進行相應的接口回調。

3、回調接口順序

 結合以前幾節內容,能夠獲得以下的回調順序:

file

 以上爲大體的過程,不含其它的回調接口,如有其它回調接口能夠按照順序依次加入。

file

我的公衆號:啊駝

原文出處:https://www.cnblogs.com/cxyAtuo/p/11626648.html

相關文章
相關標籤/搜索