Spring IOC容器創建bean過程淺析


1. 背景

Spring框架本身非常龐大,源碼閱讀可以從Spring IOC容器的實現開始一點點了解。然而即便是IOC容器,代碼仍然是非常多,短時間內全部精讀完並不現實
本文分析比較淺,而完整的IOC創建bean實際上是非常復雜的。本文對於BeanDefinition的加載解析,bean實例化的反射調用細節不作介紹,僅以較為粗略的角度來大體感受IOC容器創建bean的過程。

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

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是否為單例/原型等等。


可以看到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企業開發時必然會用到的接口,它含有許多面向框架的特性,也對應用環境作了適配。

從上面的圖中,我們可以看到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開始看起。

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

我們以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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM