Spring IOC容器建立bean過程淺析

1. 背景

Spring框架自己很是龐大,源碼閱讀能夠從Spring IOC容器的實現開始一點點了解。然而即使是IOC容器,代碼仍然是很是多,短期內所有精讀完並不現實
本文分析比較淺,而完整的IOC建立bean其實是很是複雜的。本文對於BeanDefinition的加載解析,bean實例化的反射調用細節不做介紹,僅以較爲粗略的角度來大致感覺IOC容器建立bean的過程。java

本文涉及的Spring源碼版本爲4.3.5.RELEASE。spring

2. 想要了解什麼

下面就拋出幾個想要了解的問題,也是本文介紹所要圍繞的關鍵點。緩存

  • BeanFactory和ApplicationContext的區別
  • IOC容器建立Bean的大體過程
  • Bean的循環依賴是如何解決的
  • 那些Aware到底是什麼

3. 從源碼中找出問題的答案

3.1 BeanFactory & ApplicationContext

3.1.1 BeanFactory體系

org.springframework.beans.factory.BeanFactory是Spring的Bean容器的一個很是基本的接口,位於spring-beans模塊。它包括了各類getBean方法,如經過名稱、類型、參數等,試圖從Bean容器中返回一個Bean實例。還包括諸如containsBean, isSingleton, isPrototype等方法判斷Bean容器中是否存在某個Bean或是判斷Bean是否爲單例/原型等等。app


能夠看到BeanFactory向下主要有三條繼承路線框架

  • ListableBeanFactory
    在BeanFactory基礎上,支持對Bean容器中Bean的枚舉。
  • HierarchicalBeanFactory -> ConfigurableBeanFactory
    HierarchicalBeanFactory有個getParentBeanFactory方法,使得Bean容器具備親緣關係。而ConfigurableBeanFactory則是對BeanFactory的一系列配置功能提供了支持。
  • AutowireCapableBeanFactory
    提供了一系列用於自動裝配Bean的方法,用戶代碼比較少用到,更可能是做爲Spring內部使用。

3.1.2 ApplicationContext體系

org.springframework.context.ApplicationContext是Spring上下文的底層接口,位於spring-context模塊。它能夠視做是Spring IOC容器的一種高級形式,也是咱們用Spring企業開發時必然會用到的接口,它含有許多面向框架的特性,也對應用環境做了適配。ide

從上面的圖中,咱們能夠看到ApplicationContext做爲BeanFactory的子接口,與BeanFactory之間也是經過HierarchicalBeanFactory與ListableBeanFactory橋接的。
ApplicationContext接口,繼承了MessageSource, ResourceLoader, ApplicationEventPublisher接口,以BeanFactory爲主線添加了許多高級容器特性。工具

3.2 Spring建立Bean的大體過程

搞清楚整個Spring IOC容器建立Bean的過程,對於閱讀源碼的效率會有很大的提高。
下面梳理一下整個過程:源碼分析

  1. 實例化BeanFactoryPostProcessor實現類
  2. 調用BeanFactoryPostProcessor#postProcessBeanFactory
  3. 實例化BeanPostProcessor實現類
  4. 調用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
  5. 實例化Bean
  6. 調用InstantiationAwareBeanProcessor#postProcessAfterInstantiation
  7. 調用InstantiationAwareBeanPostProcessor#postProcessPropertyValues
  8. 爲Bean注入屬性
  9. 調用BeanNameAware#setBeanName
  10. 調用BeanClassLoaderAware#setBeanClassLoader
  11. 調用BeanFactoryAware#setBeanFactory
  12. 調用BeanPostProcessor#postProcessBeforeInitialization
  13. 調用InitializingBean#afterPropertiesSet
  14. 調用Bean的init-method
  15. 調用BeanPostProcessor#postProcessAfterInitialization

3.3 IOC容器依賴注入

完整來講,IOC容器的初始化過程當中作了在容器中創建BeanDefinition的數據映射。以後全部的依賴的注入都依託於已經存在的BeanDefinition,限於篇幅,此處略去對BeanDefinition的創建做介紹。直接從上下文的getBean開始看起。post

在AbstractApplicationContext抽象類中有一個getBeanFactory方法用於返回一個ConfigurableListableBeanFactory,全部BeanFactory接口的方法實際上都委託給子類內部的ConfigurableListableBeanFactory實現。ui

咱們以AnnotationConfigApplicationContext,它在被構造時,內部的beanFactory其實是由父類GenericApplicationContext來初始化一個DefaultListableBeanFactory的。

所以咱們看某個bean是如何被加載的能夠從DefaultListableBeanFactory的getBean方法看起,對於DefaultListableBeanFactory而言那些getBean方法實際上在AbstractBeanFactory這一層就都已經實現了,而且都委託給了AbstractBeanFactory#doGetBean。下面就來看一下doGetBean方法。

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

    final String beanName = transformedBeanName(name);
    Object bean;

    /*
     * 嘗試從緩存中拿取一個bean實例。
     * Spring會在Bean還沒徹底初始化完畢的前,經過一個ObjectFactory提早暴露出bean實例,這樣爲解決循環依賴提供了遍歷。
     */
    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 + "'");
            }
        }
        // 對FactoryBean的狀況進行特殊處理。
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // 若是正在建立的bean爲原型而且已經正在建立,這種循環依賴是沒法解決的,要拋出異常。
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // 若是該beanFactory中不包含要建立bean的beanDefinition,則嘗試從父beanFactory中尋找。
        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);
            }
        }

        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // 有些bean是有depends-on/@DependsOn的,須要先初始化這些依賴。
            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);
                    getBean(dep);
                }
            }

            // 建立單例bean。
            if (mbd.isSingleton()) {
                /*
                 * 調用父類DefaultSingletonBeanRegistry的getSingleton,具體建立bean的工做實際上仍然是
                 * 回調參數中傳遞的ObjectFactory#getObject方法,而createBean其實是子類AbstractAutowireCapableBeanFactory實現的。
                 */
                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;
                        }
                    }
                });
                // 對FactoryBean的狀況進行特殊處理。
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            // 建立原型bean。
            else if (mbd.isPrototype()) {
                Object prototypeInstance = null;
                try {
                    // 前置處理,維護prototypesCurrentlyInCreation,加入當前bean記錄。
                    beforePrototypeCreation(beanName);
                    // 委託給子類AbstractAutowireCapableBeanFactory來完成具體的建立bean工做。
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    // 後置處理,維護prototypesCurrentlyInCreation信息,刪除當前bean記錄。
                    afterPrototypeCreation(beanName);
                }
                // 對FactoryBean的狀況進行特殊處理。
                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, 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) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // 到這裏一個bean就已經建立完了,最後一步檢查類型,若是不匹配會嘗試轉換。
    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
        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;
}

上面針對AbstractBeanFactory#doGetBean方法進行了源碼分析,從中咱們能夠看出它主要會幹這幾件事情:

  1. 轉換beanName。
  2. 嘗試從緩存的單例中拿實例。
  3. 若是要建立的bean是原型模式,且已經在嘗試建立,這種循環依賴是沒法解決的。
  4. 當前beanFactory不包含要建立的bean的beanDefinition,會嘗試從parentBeanFactory中獲取。
  5. 若是當前bean有依賴(xml的話就是有depends-on,註解的話有@DependsOn),則須要先完成那些bean的建立初始化。
  6. 針對scope分類討論建立。咱們比較關心的就是單例,其次是原型。
  7. 類型檢查,而且嘗試轉換。

咱們通常比較關心的就是單例bean和原型bean的建立。
在獲取單例bean時doGetBean方法會調用父類DefaultSingletonBeanRegistry#getSingleton。能夠把DefaultSingletonBeanRegistry看成一個「單例bean桶」,由於它確實就是一個用來存放單例bean的桶。可是這個桶自己不關心bean到底該怎麼建立,因此對於桶裏尚未的bean,它將建立bean的職責經過回調ObjectFactory#getObject來完成,而AbstractBeanFactory中傳遞給getSingleton方法的ObjectFactory#getObject的具體實現是調用createBean,這個方法是真正建立並初始化bean的方法,由子類AbstractAutowireCapableBeanFactory完成。
對於獲取原型bean則簡單多了,不用關心放到桶裏緩存的事情,直接調用createBean建立就是了。

因此咱們接下來經過AbstractAutowireCapableBeanFactory來看一下一個Bean具體是如何建立並初始化的。

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    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 {
        /* 
         * 在對象被實例化前,這裏有一個短路邏輯,會調用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation。
         * 若是存在某個InstantiationAwareBeanPostProcessor的調用結果不爲null,則造成了短路,接下來調用BeanPostProcessor#postProcessAfterInitialization。
         *
         * 實際上,通常Spring裏默認就LazyInitTargetSourceCreator和QuickTargetSourceCreator可能會使得這裏的短路生效。
         * 大部分狀況AOP仍是在bean被正常實例化後經過調用postProcessAfterInitialization實現的。
         */
        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);
    }

    // 建立bean的主要方法。
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    if (logger.isDebugEnabled()) {
        logger.debug("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
}

從上面能夠看到AbstractAutowireCapableBeanFactory#createBean是建立bean的主要入口方法,但仍然不是最主要在「幹活」的方法。繼續向下看doCreateBean方法。

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

    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        // 嘗試從factoryBean緩存中獲取。
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 建立bean實例。
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

    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;
        }
    }

    /*
     * Spring爲了解決單例bean的循環引用問題,會在bean尚未徹底初始化完畢前經過添加singletonFactory
     * 使得其它bean能夠拿到某個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");
        }
        addSingletonFactory(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {
                return getEarlyBeanReference(beanName, mbd, bean);
            }
        });
    }

    // 接下去初始化bean。
    Object exposedObject = bean;
    try {
        // 填充bean中的屬性。
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            /*
             * 調用初始化方法,好比:
             * 1. 各類aware回調
             * 2. 調用BeanPostProcessor#postProcessBeforeInitialization
             * 3. 調用InitializingBean#afterPropertiesSet, xml中的init-method
             * 4. 調用BeanPostProcessor#postProcessAfterInitialization
             */
            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);
        /*
         * 上面的getSingleton第二個參數爲false表示不會主動觸發early reference的建立。
         * 因此此處earlySingletonReference只有在bean建立過程當中發現有別的bean與當前bean有循環依賴纔不爲空。
         */
        if (earlySingletonReference != null) {
            /*
             * 若是當前bean調用initializeBean沒有加強原始bean實例,則取earlySingletonReference。
             * 
             * 舉例:
             * BeanA與BeanB互相依賴。Srping先建立BeanA,再建立BeanB。
             * BeanA經過addSingletonFactory暴露了獲取BeanA引用的途徑。
             *
             * 在populateBean的時候須要注入BeanB,而BeanB又須要注入BeanA,
             * 則在獲取BeanA時會調用原先BeanA暴露的ObjectFactory,繼而使得earlySingletonObjects中加入了BeanA引用。
             *
             * 回到BeanA的建立過程,走到此步時,發現initializeBean沒有加強原始bean實例,
             * 則須要取其它循環依賴bean拿BeanA時在registry留下的結果(原始bean通過SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference回調)。
             */
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                // 獲取當前bean依賴的其它bean。
                String[] dependentBeans = getDependentBeans(beanName);
                // 過濾篩選出真正依賴的bean。
                Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                /*
                 * 舉例:
                 * BeanA與BeanB互相依賴。Srping先建立BeanA,再建立BeanB。
                 * BeanA的建立走到這裏時會拋出異常。
                 *
                 * 緣由是上面的exposedObject != bean說明initializeBean方法的調用加強了原始的BeanA。
                 * 而BeanB中注入的BeanA極可能是原始beanA(可能會有SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference回調,
                 * 也就是BeanB中注入的BeanA不是此處BeanA的最終版exposedObject。
                 */
                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.");
                }
            }
        }
    }

    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

3.4 Bean的循環依賴是如何解決的

不是全部的循環依賴Spring都可以解決的。

  • 對於最簡單的狀況,bean爲單例,且使用Autowired或者setter注入,Spring是能夠解決這樣的循環依賴的。經過上面的代碼中咱們能夠看出,在一個Bean實例化後,會調用addSingletonFactory方法,在IOC容器中經過一個ObjectFactory暴露出能夠獲取還未徹底初始化完畢的bean引用。若存在循環依賴,則依賴的bean能夠在調用getBean時經過getSingleton方法獲取到循環依賴的bean。

  • 可是Spring是不容許出現原型環的,舉例來講,BeanA和BeanB循環依賴且scope都爲prototype。由於prototype的bean,不會觸發addSingletonFactory,即每次get這樣的bean都會新建立一個。因此建立BeanA須要注入一個BeanB,而這個BeanB又須要注入一個新的BeanA,這樣的循環依賴是沒辦法解決的。Spring會判斷當前bean是不是prototype而且已經在建立中,而後拋出異常。

  • 對於構造器依賴,能夠做一下討論,下面討論的bean的scope都爲單例
    • 若是BeanA構造器中依賴BeanB,而且BeanA先建立,則不管BeanB以哪一種形式依賴BeanA,都沒辦法解決這樣的循環依賴。由於實例化BeanA須要先獲得BeanB(此時還未提早暴露引用),BeanB依賴BeanA,可是拿不到BeanA提早暴露的引用,這就造成了無限循環。這種狀況會在BeanB試圖獲取BeanA時在beforeSingletonCreation方法拋出異常。
    • 若是BeanA非構造器依賴BeanB,而且BeanA先建立,BeanB即便構造器依賴BeanA,也能夠進行解決循環依賴。 由於這種狀況BeanB能夠拿到BeanA提早暴露的引用。

3.5 那些Aware到底是什麼

Spring中有不少XXXAware接口,從字面意思上很容易理解:就是bean可以「感知」XXX。一般這些接口的方法都是setXXX。在項目裏作一個工具類實現ApplicationContextAware接口,裏面能夠塞一個ApplicationContext實例到靜態域中,在代碼中就能夠很方便獲取到Spring上下文進行一些操做。

那麼Spring對於這些Aware接口是在哪一步調用的呢?答案其實在上面的源碼分析中已經提到。在AbstractAutowireCapableBeanFactory#initializeBean方法中,Spring默認會對實現BeanNameAware, BeanClassLoaderAware, BeanFactoryAware進行回調,爲它們注入beanName, classLoader, beanFactory等。

而對於更多的一些擴展,Spring基於那些processor實現了很強的可拓展性與可插拔性。好比咱們很是熟悉的ApplicationContextAware接口其實是經過ApplicationContextAwareProcessor來實際調用的,它繼承了BeanPostProcessor,其中postProcessBeforeInitialization方法中會對EnvironmentAware, EmbeddedValueResolverAware, ApplicationContextAware等等一系列Aware接口的子類Bean進行回調,爲其注入相關資源。

那麼ApplicationContextAwareProcessor是何時出如今BeanPostProcessor集合中的呢?在AbstractApplicationContext#prepareBeanFactory方法中,Spring有以下代碼:

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

也就是當Spring上下文在初始化prepareBeanFactory的時候就已經添加了ApplicationContextAwareProcessor。

相關文章
相關標籤/搜索