Spring源碼解讀之IOC容器

本節介紹神祕的IOC容器,探究IOC是怎樣工作的?Bean創建的時機是怎樣的?以及Spring是如何解決循環bean依賴的?當了解這些之後,遇到Spring報的一些錯就不會無裏頭了。俗話說一圖勝似千言萬語,先上圖, 依據自己對源碼的分析和了解大概將IOC的知識點分爲這幾塊。

                                 <0>IOC容器涉及知識點

在進入正文之前大概先對以上六點做一個整體介紹,認識一下它們是怎麼回事。

1、Bean生命週期Bean的實例化-->Bean的初始化(初始化方法、屬性賦值)-->Bean的使用-->bean銷燬。

注:標註紅色五角星是bean實例化流程中最重要的三部分,將會在getBean()流程中詳細講解。

                                                                      <1>Bean的實例化流程圖

2、循環依賴:

  • 構造器循環依賴 ---- 無解,將拋出BeanCurrentlyInCreationException異常表示循環依賴
  • field屬性的循環依賴
    • setter循環依賴 ---- spring可以通過提前曝光進行解決)
    • prototype作用域bean的循環依賴 ---- 因爲不做緩存所以無解

Spring怎麼解決循環依賴?

        ①singletonFactories 、earlySingletonObjects、singletonObjects三級緩存。

        ②創建Bean的時候會提前曝光,在屬性賦值的時候,會先將通過構造器創建出來的(還沒初始化,屬性值還都是null)bean給暴露出來,給屬性引用。

3、常用擴展點(前置後置增強):

InstantiationAwareBeanPostProcessor:   實例化前後 
    postProcessBeforeInstantiation()
    postProcessAfterInstantiation()

BeanPostProcessor:  初始化前後
    postProcessBeforeInitialization()
    postProcessAfterInitialization()
區別:Instantiation表示實例化,Initialization表示初始化。實例化的意思在對象還未生成,初始化的意思在對象已經生成。

InstantiationAwareBeanPostProcessor接口的主要作用在於目標對象的實例化過程中需要處理的事情,包括實例化對象的前後過程以及實例的屬性設置;BeanPostProcessor接口允許在調用初始化方法前後對Bean進行額外的處理。Bean後置處理器對IOC容器裏的所有Bean實例逐一處理,而非單一實例。其典型應用是:檢查Bean屬性的正確性或根據特定的標準更改Bean的屬性。

4、BeanFactory和ApplicationContext前世今生:

spring的兩種容器:a、BeanFactoy
                               b、ApplicationContext應用上下文   

 ApplicationContext和BeanFactory都是用於加載 bean 的,但是ApplicationContext提供了更多的功能,包含了BeanFactory的所有功能。

BeanFactory:BeanhFactory使用延遲加載所有的Bean,爲了從BeanhFactory得到一個Bean,只要調用getBean()方法,就能獲得Bean。

ApplicationContext除了提供上述BeanFactory所能提供的功能之外,還提供了更完整的框架功能:

      a. 國際化支持
      b. 資源訪問:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”
      c. 事件傳遞:通過實現ApplicationContextAware接口

5、無所不知的Aware:

Aware是一個具有標識作用的超級接口,實現該接口的bean是具有被spring 容器通知的能力的,而被通知的方式就是通過回調。也就是說:直接或間接實現了這個接口的類,都具有被spring容器通知的能力。

《1、Bean生命週期》中的介紹的第3步檢查Aware接口並設置相關依賴 ----- invokeAwareMethods(),則是通過回調設置beanName。例如實現了BeanNameAware則具備獲取獲得到容器中Bean的名稱的能力。

6、Context的初始化過程:

    context的出初始化依舊離不開接口ApplicationContext;AbstractApplicationContext是它的抽象基礎類,無論是XML文件配置的還是基於註解配置的Bean,其最終都是真正從下圖開始,只不過是前期BeanDefinition的處理不同而已。

                                                              <2>Context的初始化主要步驟圖


正文:

IOC容器:IOC全程爲Inversion of Control,即控制反轉,就是由 Spring IOC 容器來負責對象的生命週期和對象之間的關係。白話不多說僅此一句就夠了。下面來自讓我們真正進入spring內部,瞭解IOC的思想以及技術點。

目錄

目錄

一、前期認識:

二、Bean 的生命週期:

三、循環依賴:

四、常用擴展點(前置後置增強):

五、BeanFactory和ApplicationContext前世今生:

六、無所不知的Aware:

七、Context的初始化過程:



一、前期認識:

剛開始我們先介紹下關鍵的幾個類以及它們各自扮演的角色和關係。

  • DefaultListableBeanFactory :: preInstantiateSingletons()----->getBean()context初始化時獲取bean入口

        DefaultListableBeanFactory是整個bean加載的核心部分,是Spring註冊及加載bean的默認實現(即所有的BeanDefinition就是註冊在此類的map中),它是一個基於bean定義對象的成熟bean工廠,典型的用法是在訪問beans之前(即項目啓動的時候)註冊所有的Bean;

        而XmlBeanFactory對DefaultListableBeanFactory類進行了擴展,主要用於從XML文檔中讀取BeanDefinition,對於註冊及獲取Bean都是使用從父類DefaultListableBeanFactory繼承的方法去實現,而唯獨與父類不同的個性化實現就是增加了XmlBeanDefinitionReader類型的reader屬性。

  • AbstractBeanFactory :: doGetBean()真正獲取bean的方法

         AbstractBeanFactory 繼承DefaultSingletonBeanRegistry並實現了ConfigurableBeanFactory,因此該類具有管理、註冊、緩存單例bean能力,並且增加了對FactoryBean的特殊處理功能。

  • DefaultSingletonBeanRegistry :: getSingleton()獲取單例bean

        它繼承SimpleAliasRegistry類和實現了SingletonBeanRegistry接口,因此這個類可以有別名註冊的功能和單例bean註冊的功能(緩存單例bean--map),並且還支持註冊DisposableBean實例;它依賴ObjectFactory接口和DisposableBean接口(關閉註冊表時調用到了destroy方法)。

  • AbstractAutowireCapableBeanFactory :: doCreateBean()創建bean實例

        綜合AbstractBeanFactory並對接口AutowireCapableBeanFactory進行實現。供bean的創建 (有construct方法), 屬性注值, 綁定 (包括自動綁定)和初始化。處理運行時bean引用, 解析管理的集合, 調用初始化方法。提供通過屬性name、屬性type以及構造器的注入

                                                                            圖<1-1>創建bean關鍵類圖

二、Bean 的生命週期:

1、bean的作用域:

singleton(缺省作用域) 在整個應用中,只創建bean的一個實例,在IOC容器中共享,容器創建的時候就實例化了這個bean
prototype

每次注入或者通過Spring應用上下文獲取的時候,都會創建一個新的bean實例,相當於每次都new bean(),容器創建的時候沒有實例化了bean,而是在請求獲取的時候纔會創建對象

request

每次http請求都會創建一個bean實例,這個bean實例只在當前request請求內有效,請求結束的時候,這個bean實例被銷燬;該作用域僅適用於WebApplicationContext環境

session 同一個http session共享一個bean實例,不同的Session使用不同的Bean,該作用域僅適用於WebApplicationContext環境
globalSession 一般用於Prolet應用環境,該作用域僅適用於WebApplicationContext環境

2、生命週期從Bean實例化開始

     概述的圖<1>中便是Bean實例化的大致流程圖,實例化所涉及的關鍵類的類圖如圖<1-1>注意黃色註釋的四個類:

  • DefaultListableBeanFactory :: preInstantiateSingletons()----->getBean()獲取bean的地方
  • AbstractBeanFactory :: doGetBean()真正獲取bean的方法
  • DefaultSingletonBeanRegistry :: getSingleton()獲取單例bean
  • AbstractAutowireCapableBeanFactory :: doCreateBean()創建bean實例

在深入源碼之前綜合概述中的流程圖,先宏觀分析對源碼做個大概的瞭解:

                                                    圖<2-1>bean實例化流程分析

讀過這個圖,大家可能對第二步-->第三步有點疑問,ObjectFactory接口類的getObject()爲什麼會直接調用createBean(...)方法,其實ObjectFactory是一個函數式接口,調用getObject()時,其實真正回去回調getSIngleton(...)參數中的函數表達式()->createBean(...)。

通過宏觀分析,讓我們對Bean的實例化過程有一個大概的思路,下面開始深入源碼一步步解讀:

首先在正式分析createBean(String, RootBeanDefinition, Object[])方法前,我們先來看看 createBean 方法是在哪裏被調用的(如下圖代碼)。doGetBean 方法的代碼片段,從中可以發現 createBean 方法被匿名工廠類ObjectFactory的 getObject 方法包裹,但這個匿名工廠類對象並未直接調用 getObject 方法。而是將自身作爲參數傳給了getSingleton(String, ObjectFactory)方法,createBean ()真正是在getSingleton()方法中回調的。

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

		// ...省略...
        /********* 1、先從緩存中取 **********/
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			// ...省略...
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
       /********* 2、緩存中中沒有就創建 **********/
		else {
			
           /********* 2.1、 如果是原型bean並且正在被創建,則報異常(循環依賴會在第三部分介紹)**********/
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
		
            /********* 2.2、標記正在被創建 **********/
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

            /********* 2.2、單例bean開始創建**********/
			// Create bean instance.
			if (mbd.isSingleton()) {
                  /********* 2.3、開始獲取單例bean*********/
				sharedInstance = getSingleton(beanName, () -> {
					try {
                /********* 2.4 createBean 方法被匿名工廠類的 getObject 方法包裹,
                       但這個匿名工廠類對象並未直接調用 getObject方法,而是將自
                      身作爲參數傳給了2.3步的getSingleton(String, ObjectFactory)
                      方法*********/
					  return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
					
				          destroySingleton(beanName);
				          throw ex;
				    }
			   });
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
		}
	}		
		
	return (T) bean;
}

doGetBean 方法的大概處理步驟如下(代碼中有每一步相關注釋):

    1. 先從緩存中取,取緩存順序依次是singletonObjects-->earlySingletonObjects-->singletonFactories,取到就直接返回。
    2. 若爲空,如果是原型bean並且正在被創建,則報異常
    3. 若是單例bean,則標記正在被創建
    4. 開始創建單例Bean,createBean 方法被匿名工廠類的 getObject 方法包裹,但這個匿名工廠類對象並未直接調用
getObject 方法,而是在getSingleton(String, ObjectFactory)方法中回調。

代碼中註釋的2.1也解釋了prototype作用域bean的循環依賴Spring是無助的。

從上面代碼分析createBean()是在getSingleton(String, ObjectFactory)方法中回調的,我們來具體分析下此方法是如何處理的。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "'beanName' must not be null");
    synchronized (this.singletonObjects) {
        // 1、從緩存中獲取單例 bean,若不爲空,則直接返回,不用再創建
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // ....省略....
            /* 
             * 2、將 beanName 添加到 singletonsCurrentlyInCreation 集合中,
             * 用於表明 beanName 對應的 bean 正在創建中(表明單例bean正在創建中)
             */
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<Exception>();
            }
            try {
                /*****3、通過 getObject 方法調用 createBean 方法創建 bean 實例***/
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                 // ....省略....
            }
            catch (BeanCreationException ex) {
                 // ....省略....
            }
            finally {
               
                /***4、 將 beanName 從 singletonsCurrentlyInCreation 移除***/
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                /* 
                 * 5、將 <beanName, singletonObject> 鍵值對添加到 singletonObjects 集合中,
                 * 並從其他集合(比如 earlySingletonObjects)中移除 singletonObject 記錄
                 */
                addSingleton(beanName, singletonObject);
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
}

getSingleton(String, ObjectFactory)只看關鍵代碼其邏輯不是很複雜,大概處理邏輯如下(代碼中每一步也有相關注釋):

  1. 先從 singletonObjects 集合獲取 bean 實例,若不爲空,則直接返回
  2. 若爲空,進入創建 bean 實例階段。先將 beanName 添加到 singletonsCurrentlyInCreation
  3. 通過 getObject 方法回調getSingleton(String, ObjectFactory)的入參 createBean() 方法創建 bean 實例
  4. 無論是否創建成功最終都會將 beanName 從 singletonsCurrentlyInCreation 集合中移除
  5. 將 <beanName, singletonObject> 映射緩存到 singletonObjects (緩存所有的單實例bean)集合中

從上面的分析中,我們知道了 createBean 方法在何處被調用的。那麼接下來我們一起重點深入 createBean 方法的源碼中,來看看這個方法具體都做了什麼事情。

AbstractAutowireCapableBeanFactory::
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		
		RootBeanDefinition mbdToUse = mbd;

		// ... 省略...

		try {
			/**** 1、Give BeanPostProcessors a chance to return a proxy instead of the 
              *** target bean instance.(實例化前後置處理,如果不爲空則直接返回,一般bean創建 
              *** 都爲空)
              *** 問題:爲什麼spring是在初始化之後proxy而不是resolveBeforeInstantiation
              *** resolveBeforeInstantiation只是針對有自定義的targetsource,因爲自定義的
              *** targetsource不是spring的bean那麼肯定不需要進行後續的一系列的實例化 初始化。所以
              ***  可以在resolveBeforeInstantiation直接進行proxy
              ***/
			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 {
            /****2、開始真正創建bean******/
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("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);
		}
	}

createBean 方法處理較爲簡單,主要是有一個預處理-----後置處理器處理(代碼中的第1步),當然對於一般的bean處理結果都返回空;然後真正創建bean的邏輯是在doCreateBean()方法中;這個doxxx()是Spring框架中經常用的,往往在做某件事情之前都會做一些預備工作,最終的處理邏輯在doxxx()方法中。

AbstractAutowireCapableBeanFactory::
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		/* 
         * BeanWrapper 是一個基礎接口,由接口名可看出這個接口的實現類用於包裹 bean 實例。
         * 通過 BeanWrapper 的實現類可以方便的設置/獲取 bean 實例的屬性
         */
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}

        /* 
         * 1.反射創建 bean 實例,並將實例包裹在 BeanWrapper 實現類對象中返回。 
         * createBeanInstance 中包含三種創建 bean 實例的方式:
         *   ①. 通過工廠方法創建 bean 實例
         *   ②. 通過構造方法自動注入(autowire by constructor)的方式創建 bean 實例
         *   ③. 通過無參構造方法方法創建 bean 實例
         *
         *   注意:若 bean 的配置信息中配置了 lookup-method 和 replace-method,則會使用  
         *   CGLIB增強 bean 實例。(可以先不關注,只關注主流程創建bean實例)
         */
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}

        /*** 補充:此處創建的bean是一個原始的bean,並沒有任何屬性填充和初始化。**/
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// ...省略...

    /*
     * 2、(解決循環依賴)earlySingletonExposure 是一個重要的變量,這裏要說明一下。該變量用於表
     * 示是否提前暴露單例 bean,用於解決循環依賴。切記:此處的bean是原始bean,並沒有屬性賦值和初
     * 始化,因爲是引用,所以bean初始化完成之後就會變成完整的bean。 
     * earlySingletonExposure 由三個條件綜合而成,如下:
     *   條件1:mbd.isSingleton() - 表示 bean 是否是單例類型
     *   條件2:allowCircularReferences - 是否允許循環依賴
     *   條件3:isSingletonCurrentlyInCreation(beanName) - 當前 bean 是否處於創建的狀態中
     * 
     * earlySingletonExposure = 條件1 && 條件2 && 條件3 
     *                        = 單例 && 是否允許循環依賴 && 是否存於創建狀態中。
     */
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
             /** 補充:獲取獲取原始對象早期 bean 的引用,如果 bean 中的方法被 AOP 切點所匹配 
              ** 到,在 getEarlyBeanReference 方法中,會執行 AOP 相關邏輯。 
              ** 若 bean 未被 AOP 攔截,getEarlyBeanReference 原樣返回 
              ** bean,所以大家可以把
              **      return getEarlyBeanReference(beanName, mbd, bean) 
              ** 等價於:
              **      return bean;
              **/
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
              /*** 3、屬性賦值,稍後專門分析***/
			populateBean(beanName, mbd, instanceWrapper);
            /*
             * 4、進行餘下的初始化工作,詳細如下:
             *   ①. 判斷 bean 是否實現了 BeanNameAware、BeanFactoryAware、
             *    BeanClassLoaderAware 等接口,並執行接口方法
             *   ②. 應用 bean 初始化前置操作
             *   ③. 如果 bean 實現了 InitializingBean 接口,則執行 afterPropertiesSet 
             *      方法。如果用戶配置了 init-method,則調用相關方法執行自定義初始化邏輯
             *   ④. 應用 bean 初始化後置操作
             * 
             * 另外,AOP 相關邏輯也會在該方法中織入切面邏輯,此時的 exposedObject 就變成了
             * 一個代理對象了
             */
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			
		}

		// ...省略...

		// Register bean as disposable.
		try {
        /**** 5、註冊銷燬邏輯***/
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			
		}

		return exposedObject;
	}

三、循環依賴:

依據第二節的Bean實例化步驟分析,我們來做一個簡單的流程分析:
       1. 創建原始 bean 實例 → createBeanInstance(beanName, mbd, args)
       2. 添加原始對象工廠對象到 singletonFactories 緩存中 → addSingletonFactory(beanName, () ->  getEarlyBeanReference(beanName, mbd, bean));                 
       3. 填充屬性,解析依賴 → populateBean(beanName, mbd, instanceWrapper)

重點來了,addSingletonFactory()就是解決循環依賴的關鍵點,因爲此方法可以將原始對象的引用提早加入緩存以進行曝光。舉個例子,假設 ClassA和ClassB相互依賴,那麼實例化ClassA時通過方法addSingletonFactory()先將自己的原始Bean加入緩存提前暴露引用,然後在調用populateBean()進行屬性填充時,發現依賴ClassB,然後就會首先實例化ClassB;ClassB當遇到這個方法時也會解析自己的依賴,然後對於ClassA這個依賴,會在getSington(String beanName)時獲取到早期暴露的原始bean,獲取到依賴的早期bean之後,ClassB就可以完成實例化工作,然後ClassA就可以獲取到完整的ClassB實例,最後再會退回來繼續實例化ClassA,當Class完成實例化之後ClassA和ClassB之間就完成了完整的bean依賴也處於可用狀態。

getSington(String beanName)具體源碼如下,源碼中提到了獲取bean時的幾個緩存,同時在概述的第2節我們也提到了這幾個緩存,下面詳細介紹下這幾個緩存:

緩存 容器 作用
singletonObjects Map(key=beanName,value=bean實例) 用於存放完全初始化好的 bean,從該緩存中取出的 bean 可以直接使用
earlySingletonObjects Map 存放原始的 bean 對象(尚未填充屬性),用於解決循環依賴
singletonFactories Map 存放 bean 工廠對象,用於解決循環依賴

        getSington(String beanName)是在doGetBean()方法中調用的(可以看上一節創建bean實例源碼分析),從代碼中分析邏輯很簡單:
1. 首先從 singletonObjects 緩存中獲取 bean 實例。
2. 若未命中,再去 earlySingletonObjects 緩存中獲取原始 bean 實例。
3. 如果仍未命中,則從 singletonFactory 緩存中獲取 ObjectFactory 對象,然後再調用 getObject 方法獲取原始 bean 實例的應用,也就是早期引用。
4. 獲取成功後,將該實例放入 earlySingletonObjects 緩存中,並將 ObjectFactory 對象從 singletonFactories 移除。

DefaultSingletonBeanRegistry::
	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}


	@Nullable
	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) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
                        /**** 從緩存中拿到早期原始bean *****/
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

最後一張圖來結束這一小節:

四、常用擴展點(前置後置增強):

依舊是先上圖讓我們對bean的增強器的作用點有大概的宏觀瞭解,如下圖所示,其實簡單理解就是:

bean實例化前後分別會由InstantiationAwareBeanPostProcessor的前置和後置處理方法去處理,而在初始化前後會由BeanPostProcessor的前置和後置處理方法處理。

注意區別:InstantiationAwareBeanPostProcessor的兩個方法是由Instantiation結尾,表明是實例化專用;BeanPostProcessor的兩個方法是由Initialization結尾表明是初始化專用。

 

                                                                        圖<4-1>處理器在bean創建流程中的插入點

下面根據上圖以及源碼來詳細分析,有部分源碼可能和前面有重複,所以只關注本節要講述的源碼,

1、InstantiationAwareBeanPostProcessor前置代碼分析:

AbstractAutowireCapableBeanFactory::

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

	    // ...省略...
		try {
             /**** 1、Give BeanPostProcessors a chance to return a proxy instead of the 
              *** target bean instance.(實例化前後置處理,如果不爲空則直接返回,一般bean創建 
              *** 都爲空)
              *** 繼續跟進方法內部分析
              ***/
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			
		}

		try {
            /** 2、前置處理結束,開始創建bean **/
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			
		}
		catch (Throwable ex) {
			
		}
	}

---------------------------------------------------------------------------------
AbstractAutowireCapableBeanFactory::

/** 在 resolveBeforeInstantiation 方法中,當前置處理方法返回的 bean 不爲空時,後置處理纔會被執
 * 行。前置處理器是 InstantiationAwareBeanPostProcessor 類型的,該種類型的處理器一般用在 Spring
 * 框架內。
 *** 問題:爲什麼spring是在初始化之後proxy而不是resolveBeforeInstantiation
 *** resolveBeforeInstantiation只是針對有自定義的targetsource,因爲自定義的
 *** targetsource不是spring的bean那麼肯定不需要進行後續的一系列的實例化 初始化。所以
 ***  可以在resolveBeforeInstantiation直接進行proxy
 **/
	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
                    /* 
                     * 一般單例bean在這邊處理都是返回null,這邊不是重點,一般bean的創建這邊都會返
                     * 回null
                     */
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}
---------------------------------------------------------------------------------------

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        /** 1、只針對接口是InstantiationAwareBeanPostProcessor 類型的**/
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            /* 2、bean 初始化前置處理。如果返回null;後面的所有 
             * 後置處理器的方法就不執行,直接返回(所以執行順序很重要)
             */
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

總結:真正創建bean之前會給處理器一個機會看是否要給目標bean生成動態代理對象,這兒的機會主要是針對AOP的,普通的Bean創建都會返回null,然後開始按正常創建Bean的邏輯去執行doCreateBean()方法。

2、InstantiationAwareBeanPostProcessor後置代碼分析:

 實例化後置處理這部分代碼主要在populateBean()方法中,這在圖<4-1>中有體現

AbstractAutowireCapableBeanFactory::

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		
     /*
     * 1、又是給一個機會
     * 在屬性被填充前,給 InstantiationAwareBeanPostProcessor 類型的後置處理器一個修改 
     * bean 狀態的機會。關於這段後置引用,官方的解釋是:讓用戶可以自定義屬性注入。比如用戶實現一
     * 個 InstantiationAwareBeanPostProcessor 類型的後置處理器,並通過 
     * postProcessAfterInstantiation 方法向 bean 的成員變量注入自定義的信息。當然,如果無
     * 特殊需求,直接使用配置中的信息注入即可。另外,Spring 並不建議大家直接實現 
     * InstantiationAwareBeanPostProcessor 接口,如果想實現這種類型的後置處理器,更建議
     * 通過繼承 InstantiationAwareBeanPostProcessorAdapter 抽象類實現自定義後置處理器。
     */
  
		/** Give any InstantiationAwareBeanPostProcessors the opportunity to modify 
		 ** the state of the bean before properties are set. This can be used, for 
		 ** example, to support styles of field injection.
              **/
		boolean continueWithPropertyPopulation = true;

		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						continueWithPropertyPopulation = false;
						break;
					}
				}
			}
		}

		if (!continueWithPropertyPopulation) {
			return;
		}

		/... 省略....

		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

總結:這個postProcessAfterInstantiation返回值要注意,因爲它的返回值是決定要不要調用postProcessPropertyValues方法的其中一個因素(因爲還有一個因素是mbd.getDependencyCheck());如果該方法返回false,並且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果返true,postProcessPropertyValues就會被執行。

3、BeanPostProcessor的前置、後置分析源碼:

在圖<4-1>中有體現,處理器插入點其實是在init-method方法生效前後調用postProcessBeforeInitialization和postProcessAfterInitialization方法

AbstractAutowireCapableBeanFactory::

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		// ...省略...

		Object wrappedBean = bean;

		if (mbd == null || !mbd.isSynthetic()) {
      /** 1、執行 bean 初始化前置操作**/
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
        /*
         * 2、調用初始化方法:
         * ①. 若 bean 實現了 InitializingBean 接口,則調用 afterPropertiesSet 方法
         * ②. 若用戶配置了 bean 的 init-method 屬性,則調用用戶在配置中指定的方法
         */
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
 /**3、 執行 bean 初始化後置操作,注意AOP 就是在後置處理 postProcessAfterInitialization 方法
  ** 中向目標對象中織如切面邏輯的, AOP 模塊中的AbstractAutoProxyCreator抽象類間接實現了這個接口中
  * 的postProcessBeforeInstantiation方法,AOP代理的創建就是在這個方法內部循環processors,通過
  * AbstractAutoProxyCreator創建
  * 
  **/
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

總結:通過上面源碼分析在加上面流程圖解應該是很清晰了:

1、實例化完成,屬性賦值完成

2、執行初始化前置處理邏輯一般bean的創建會返回原bean

3、執行實現了接口的初始化方法

4、執行初始化後置處理邏輯一般bean的創建會返回原bean

五、BeanFactory和ApplicationContext前世今生:

Spring的IoC容器就是一個實現了BeanFactory接口的可實例化類。事實上,Spring提供了兩種不同的容器:一種是最基本的BeanFactory,另一種是擴展的ApplicationContext。BeanFactory 僅提供了最基本的依賴注入支持,而 ApplicationContext 則擴展了BeanFactory ,提供了更多的額外功能。二者對Bean的初始化也有很大區別。BeanFactory當需要調用時讀取配置信息,生成某個類的實例。如果讀入的Bean配置正確,則其他的配置中有錯誤也不會影響程序的運行。而ApplicationContext 在初始化時就把 xml 的配置信息讀入內存,對 XML 文件進行檢驗,如果配置文件沒有錯誤,就創建所有的Bean ,直接爲應用程序服務。相對於基本的BeanFactory,ApplicationContext 唯一的不足是佔用內存空間。當應用程序配置Bean較多時,程序啓動較慢。

ApplicationContext會利用Java反射機制自動識別出配置文件中定義的BeanPostProcessor、InstantiationAwareBeanPostProcessor和BeanFactoryPostProcessor,並自動將它們註冊到應用上下文中;而BeanFactory需要在代碼中通過手工調用addBeanPostProcessor()方法進行註冊。

類圖如下ApplicationContext是繼承了BeanFactory,並且也繼承了其它的接口,說明ApplicationContext是對BeanFactory接口的擴展,具備BeanFactory不具有的功能。

1、BeanFactory介紹:

Spring容器最基本的接口就是BeanFactory。BeanFactory負責配置、創建、管理Bean,它有一個子接口ApplicationContext也被稱爲Spring上下文,容器同時還管理着Bean和Bean之間的依賴關係。spring Ioc容器的實現,從根源上是beanfactory,但真正可以作爲一個可以獨立使用的ioc容器還是DefaultListableBeanFactory,因此可以這麼說,
DefaultListableBeanFactory 是整個spring ioc的始祖

BeanFactory是Spring bean容器的根接口,提供獲取bean,是否包含bean,是否單例與原型,獲取bean類型,bean 別名的方法 。它最主要的方法就是getBean(String beanName),因此前面創建Bean所介紹的主要類都實現自BeanFactory接口。

BeanFactory的三個子接口:
 * HierarchicalBeanFactory:提供父容器的訪問功能
 * ListableBeanFactory:提供了批量獲取Bean的方法
 * AutowireCapableBeanFactory:它繼承了BeanFactory接口,該接口是一個自動注入的ioc bean工廠接口,主要定義bean的創建、初始化、自動注入以及bean初始化前置、後置增強的接口;在BeanFactory基礎上實現對已存在實例的管理。

2、ApplicationContext介紹:

    ApplicationContext常用實現類 作用
AnnotationConfigApplicationContext 從一個或多個基於java的配置類中加載上下文定義,適用於java註解的方式。
ClassPathXmlApplicationContext 從類路徑下的一個或多個xml配置文件中加載上下文定義,適用於xml配置的方式。
FileSystemXmlApplicationContext 從文件系統下的一個或多個xml配置文件中加載上下文定義,也就是說系統盤符中加載xml配置文件。
AnnotationConfigWebApplicationContext 專門爲web應用準備的,適用於註解方式。
XmlWebApplicationContext 從web應用下的一個或多個xml配置文件加載上下文定義,適用於xml配置方式。
   

由於ApplicationContext會預先初始化所有的Singleton Bean,於是在系統創建前期會有較大的系統開銷,但一旦ApplicationContext初始化完成,程序後面獲取Singleton Bean實例時候將有較好的性能。也可以爲bean設置lazy-init屬性爲true,即Spring容器將不會預先初始化該bean。

六、無所不知的Aware:

spring Aware 的目的是爲了讓bean獲取spring容器的服務,Aware接口如上圖所示。

我們只介紹常用的這三個接口:

  • BeanNameAware :可以獲取容器中bean的名稱
  • BeanFactoryAware:獲取當前bean factory這也可以調用容器的服務
  • ApplicationContextAware: 當前的applicationContext, 這也可以調用容器的服務

還記得概述中 圖<1>Bean的實例化流程圖嗎,屬性賦值的下一步就是Aware接口檢查,我們來分析下源碼:
在屬性賦值之後,bean初始化之前會有一個檢查設置Aware的機會,以便爲bean提供Spring的一些資源。在invokeAwareMethods()方法中只檢測了上面三個Aware接口,那麼問題來了其他的Aware接口怎麼設值,例如開發中經常自定義實現了ApplicationContextAware用來獲取應用上下文,它的setApplicationContext()方法是在哪裏被調用的呢?
答:如果bean實現了ApplicationContextAware接口,它的setApplicationContext()方法將被調用,將應用上下文的引用傳入到bean中-------此處的調用設置其實是在處理器ApplicationContextAwareProcessor中做的,ApplicationContextAwareProcessor實現了BeanPostProcessor接口。

 


AbstractAutowireCapableBeanFactory::

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
      
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
            /** 1、檢查Aware接口並進行設置,重點介紹此方法 **/
			invokeAwareMethods(beanName, bean);
		}

        /** 2、很熟悉了,就是初始化前後增強,前面已經介紹不再多說**/
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}
=============================================================================================
/**
如果bean實現了BeanNameAware接口,spring將bean的id傳給setBeanName()方法;
如果bean實現了BeanFactoryAware接口,spring將調用setBeanFactory方法,將BeanFactory實例傳進來;
**/

	private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

七、Context的初始化過程:

Context的初始化過程在概述中<6、Context的初始化過程>已做簡單敘述,大致過程如概述中的第6小節的圖<2>所示,具體每一步我們來看源碼:

AnnotationConfigApplicationContext::

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
//準備上下文的刷新,
            prepareRefresh();
            // Tell the subclass to refresh the internal bean factory.
//得到新的Bean工廠,應用上下文加載bean就是在這裏面實現的
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//準備bean工廠用在上下文中
            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);
            try {
                // Allows post-processing of the bean factory in context subclasses.
//允許子類上下問處理bean工廠
                postProcessBeanFactory(beanFactory);
                // Invoke factory processors registered as beans in the context.
//請求工廠處理器作爲beans註冊在上下文
                invokeBeanFactoryPostProcessors(beanFactory);
                // Register bean processors that intercept bean creation.
//註冊bean處理器攔截bean創建
                registerBeanPostProcessors(beanFactory);
                // Initialize message source for this context.
//初始化上下文中消息源
                initMessageSource();
                // Initialize event multicaster for this context.
//初始化上下文中事件廣播
                initApplicationEventMulticaster();
                // Initialize other special beans in specific context subclasses.
//初始化其他具體bean
                onRefresh();
                // Check for listener beans and register them.
//檢查監聽bean並註冊
                registerListeners();
                // Instantiate all remaining (non-lazy-init) singletons.
//實例化未初始化單例
                finishBeanFactoryInitialization(beanFactory);
                // Last step: publish corresponding event.
//最後一步發佈相應事件
                finishRefresh();
            }

AnnotationConfigApplicationContext::
-------> AbstractApplicationContext: refresh() bean加載的入口
       -------> obtainFreshBeanFactory():獲取BeanFactory(返回GenericApplicationContext創建的BeanFactory對象--DefaultListableBeanFactory)
      --------> prepareBeanFactory(beanFactory);方爲了下面在Spring上下文中使用BeanFactory做準備(對剛纔創建BeanFactory對象進行一些設置屬性)
      --------> postProcessBeanFactory(beanFactory);BeanFactory準備工作完成後進行的後置處理工作;子類通過重寫這個方法來在BeanFactory創建並預準備完成以後做進一步的設置
      --------> invokeBeanFactoryPostProcessors(beanFactory);該方法的調用必須在所有的singleton實例化之前,而且從該方法的名稱可以看出來,引入了IOC的Processor角色(其實就是Bean工廠裏的處理器)。

	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	/** 就是將所有的BeanFactoryPostProcessor調用了一遍**/	
     PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

BeanFactoryPostProcessor:BeanFactory的後置處理器。在BeanFactory標準初始化之後執行,執行BeanFactoryPostProcessor的方法
    兩個接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
    1)、執行BeanFactoryPostProcessor的方法;
        先執行BeanDefinitionRegistryPostProcessor
        1)、獲取所有的BeanDefinitionRegistryPostProcessor;
        2)、看先執行實現了PriorityOrdered優先級接口的BeanDefinitionRegistryPostProcessor、
            postProcessor.postProcessBeanDefinitionRegistry(registry)
        3)、再執行實現了Ordered順序接口的BeanDefinitionRegistryPostProcessor;
            postProcessor.postProcessBeanDefinitionRegistry(registry)
        4)、最後執行沒有實現任何優先級或者是順序接口的BeanDefinitionRegistryPostProcessors;
            postProcessor.postProcessBeanDefinitionRegistry(registry)
        再執行BeanFactoryPostProcessor的方法
        1)、獲取所有的BeanFactoryPostProcessor
        2)、看先執行實現了PriorityOrdered優先級接口的BeanFactoryPostProcessor、
            postProcessor.postProcessBeanFactory()
        3)、在執行實現了Ordered順序接口的BeanFactoryPostProcessor;
            postProcessor.postProcessBeanFactory()
        4)、最後執行沒有實現任何優先級或者是順序接口的BeanFactoryPostProcessor;
            postProcessor.postProcessBeanFactory()
--------> registerBeanPostProcessors(beanFactory): 註冊BeanPostProcessor(Bean的後置處理器);不同接口類型的BeanPostProcessor,在Bean創建前後的執行時機是不一樣的。【 intercept bean creation】
--------> finishBeanInitialization(beanFactory): 這個方法裏面,用來初始化非懶加載的bean。並非所有bean都在容器啓動的時候實例化。在xml中配置bean的時候,有個lazy-ini屬性,默認爲false。所以默認情況下,單例的非懶加載的bean在容器啓動的時候會實例化。如果是懶加載的,那麼在getBean的時候,再實例化。(前面已經具體分析過)

總結:
    1)、Spring容器在啓動的時候,先會保存所有註冊進來的Bean的定義信息;
        1)、xml註冊bean;<bean>
        2)、註解註冊Bean;@Service、@Component、@Bean、xxx
    2)、Spring容器會合適的時機創建這些Bean
        1)、用到這個bean的時候;利用getBean創建bean;創建好以後保存在容器中;
        2)、統一創建剩下所有的bean的時候;finishBeanFactoryInitialization();
    3)、後置處理器;BeanPostProcessor
        1)、每一個bean創建完成,都會使用各種後置處理器進行處理;來增強bean的功能;
            AutowiredAnnotationBeanPostProcessor:處理自動注入
            AnnotationAwareAspectJAutoProxyCreator:來做AOP功能;
            xxx....
            增強的功能註解:
            AsyncAnnotationBeanPostProcessor
            ....

 

發佈了4 篇原創文章 · 獲贊 1 · 訪問量 2817
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章