?第一節講解Spring啟動的時候說到,Spring內部先解析了所有的配置,加載所有的Bean定義后,再根據需要對Bean進行實例化和初始化。除開Spring自己主動新建的對象,第一次根據Bean定義加載對象的動作出現在AbstractApplicationContext的invokeBeanFactoryPostProcessors方法,該方法會在Spring容器中找出實現了BeanFactoryPostProcessor接口的bean列表并執行。根據之前介紹的內容,內部主要調用了AbstractBeanFactory的getBean方法,這節將對該方法進行講解。

一、getBean

?在這之前,先介紹BeanFactory的層次結構,如下:

file

涉及到的接口和實現類為:

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

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

?ConcurrentHashMap:管理別名

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

?DefaultSingletonBeanRegistry:單例管理實現類,內部用Map維護著被實例化后的所有單例、單例工廠等相關信息。Map的鍵為bean的唯一標識,Spring內部成為raw name,一般等同于Bean定義中的id或者name或者別名等,具體規則可以從上節BeanDefinition的加載查看,值為相應的對象實例。這邊需要指出的一點是,對于bean定義中具有別名意義的字段,如一定情況下的name以及alias字段,只存在于SimpleAliasRegistry維護的內部Map中,通過遞歸查詢的方式可以從一個給定的別名查找到指定的id。

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

file

?FactoryBeanRegistrySupport:增加緩存FactoryBean實例功能,DefaultSingleBeanRegistry在生成單例后便不再持有對應的FactoryBean

?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還未創建。

二、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. 使用默認的構造方法進行實例化

2) 回調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對象進行存儲,并在銷毀時進行相應的接口回調。

三、回調接口順序

?結合之前幾節內容,可以得到如下的回調順序:

file

?以上為大致的過程,不含其它的回調接口,若有其它回調接口可以按照順序依次加入。

file

個人公眾號:啊駝