Spring-IOC-SingletonBean的創(chuàng)建過程

如果緩存中沒有單例Bean的緩存,則需要從頭開始創(chuàng)建單例Bean,這主要是重載getSingleton的重載方法來實(shí)現(xiàn)單例Bean的加載。

getSingleton方法

3. 獲取單例
    /**
     * Return the (raw) singleton object registered under the given name,
     * creating and registering a new one if none registered yet.
     * @param beanName the name of the bean
     * @param singletonFactory the ObjectFactory to lazily create the singleton
     * with, if necessary
     * @return the registered singleton object
     */
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "'beanName' must not be null");
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                if (this.singletonsCurrentlyInDestruction) {
                    throw new BeanCreationNotAllowedException(beanName,
                            "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                            "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                }
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<Exception>();
                }
                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                catch (IllegalStateException ex) {
                    // Has the singleton object implicitly appeared in the meantime ->
                    // if yes, proceed with it since the exception indicates that state.
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        throw ex;
                    }
                }
                catch (BeanCreationException ex) {
                    if (recordSuppressedExceptions) {
                        for (Exception suppressedException : this.suppressedExceptions) {
                            ex.addRelatedCause(suppressedException);
                        }
                    }
                    throw ex;
                }
                finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }
    }

前后處理方法:

3.1 
    /**
     * Callback before singleton creation.
     * <p>The default implementation register the singleton as currently in creation.
     * @param beanName the name of the singleton about to be created
     * @see #isSingletonCurrentlyInCreation
     */
    protected void beforeSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }
3.2 
    /**
         * Callback after singleton creation.
         * <p>The default implementation marks the singleton as not in creation anymore.
         * @param beanName the name of the singleton that has been created
         * @see #isSingletonCurrentlyInCreation
         */
    protected void afterSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
        }
    }
3.3 
    /**
     * Add the given singleton object to the singleton cache of this factory.
     * <p>To be called for eager registration of singletons.
     * @param beanName the name of the bean
     * @param singletonObject the singleton object
     */
    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
3.4 從3返回
sharedInstances = getSingleton(String beanName, ObjectFactory<?> singletonFactory)

這個(gè)方法只是做一些準(zhǔn)備以及處理操作,而真正的獲取單例bean的方法其實(shí)并不是在此方法中實(shí)現(xiàn)的,其實(shí)現(xiàn)邏輯是在ObjectFactory類型的實(shí)例singletonFactory中實(shí)現(xiàn)的。

準(zhǔn)備及處理操作如下:

  1. 首先獲取SingletonObjects的對(duì)象鎖,保證單例的全局唯一性。

  2. 檢查緩存是否已經(jīng)加載過。

  3. 若沒有加載,則記錄beanName的正在加載狀態(tài)

  4. 加載單例前記錄加載狀態(tài)

    beforeSingletonCreation()方法用于記錄加載的狀態(tài):
    調(diào)用this.singletonsCurrentlyInCreation.add(beanName)將當(dāng)前正要?jiǎng)?chuàng)建的bean記錄在緩存中,這樣便可以對(duì)循環(huán)依賴進(jìn)行檢測啦

  5. 通過調(diào)用參數(shù)傳入的ObjectFactory的getObject方法實(shí)例化bean

    singletonObject = singletonFactory.getObject();

  6. 加載單例后的處理方法調(diào)用

    當(dāng)bean加載結(jié)束后需要移除緩存中對(duì)該bean的正在加載狀態(tài)的記錄: afterSingletonCreation()方法調(diào)用

  7. 將結(jié)果記錄至緩存并刪除加載bean過程中所有記錄的各種輔助狀態(tài)

    調(diào)用addSingleton()方法

  8. 返回處理結(jié)果

    上述是加載bean的邏輯框架,現(xiàn)在為止還沒有對(duì)bean加載功能的探索,其實(shí)bean的加載邏輯是在傳入的ObjectFactory類型的參數(shù)singletonFactory中定義的,而ObjectFactory的核心代碼只是調(diào)用了createBean的方法,接下來就去探究一下這個(gè)方法的奧妙。

createBean方法詳解

準(zhǔn)備創(chuàng)建bean(createBean方法詳解)
beans.factory.support.AbstractAutowireCapableBeanFactory
    //---------------------------------------------------------------------
    // Implementation of relevant AbstractBeanFactory template methods
    //---------------------------------------------------------------------

    /**
     * Central method of this class: creates a bean instance,
     * populates the bean instance, applies post-processors, etc.
     * @see #doCreateBean
     */
    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            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);
        }

        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }

createBean方法主要步驟:

  1. 根據(jù)設(shè)置的class屬性或者根據(jù)className來解析Class。

  2. 對(duì)override屬性進(jìn)行標(biāo)記以及驗(yàn)證(是針對(duì)Spring配置中l(wèi)ookup-method、replace-method bean的子標(biāo)簽進(jìn)行處理,因?yàn)檫@兩個(gè)子標(biāo)簽的加載過程就是將配置統(tǒng)一存放在BeanDefinition中的methodOverride屬性里)。

  3. 應(yīng)用實(shí)例前的后處理器,給后處理器一個(gè)返回代理而不是目標(biāo)bean實(shí)例的機(jī)會(huì),如果返回的代理類不為空則直接返回,而不會(huì)進(jìn)行下面的創(chuàng)建bean的過程。

  4. 創(chuàng)建bean(doCreateBean方法)。這又是一個(gè)比較重要而且復(fù)雜的過程,需要仔細(xì)分析。

下面重點(diǎn)講解步驟2、3、4。

步驟2- 處理override屬性

用于處理配置中的lookup-method以及replace-method屬性。

主要完成的工作:

  1. 標(biāo)記

如果一個(gè)類中存在若干個(gè)重載方法,方法調(diào)用以及增強(qiáng)的時(shí)候還需要根據(jù)參數(shù)類型進(jìn)行匹配,來最終確定當(dāng)前調(diào)用的是哪個(gè)方法,Spring在這里將匹配的工作在這里完成匹配的,這樣在后續(xù)調(diào)用的時(shí)候變可以直接是我用找到的方法,而不需要進(jìn)行方法的參數(shù)匹配驗(yàn)證了

  1. 驗(yàn)證

在標(biāo)記的過程中可以對(duì)方法存在性進(jìn)行驗(yàn)證,一箭雙雕。

4.1 處理override屬性
beans.factory.support.AbstractBeanFactory(XmlBeanFactory 繼承自這個(gè)類,擁有這個(gè)方法)
    /**
     * Validate and prepare the method overrides defined for this bean.
     * Checks for existence of a method with the specified name.
     * @throws BeanDefinitionValidationException in case of validation failure
     */
    public void prepareMethodOverrides() throws BeanDefinitionValidationException {
        // Check that lookup methods exists.
        MethodOverrides methodOverrides = getMethodOverrides();
        if (!methodOverrides.isEmpty()) {
            Set<MethodOverride> overrides = methodOverrides.getOverrides();
            synchronized (overrides) {
                for (MethodOverride mo : overrides) {
                    prepareMethodOverride(mo);
                }
            }
        }
    }
    /**
     * Validate and prepare the given method override.
     * Checks for existence of a method with the specified name,
     * marking it as not overloaded if none found.
     * @param mo the MethodOverride object to validate
     * @throws BeanDefinitionValidationException in case of validation failure
     */
    protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
        int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
        if (count == 0) {
            throw new BeanDefinitionValidationException(
                    "Invalid method override: no method with name '" + mo.getMethodName() +
                    "' on class [" + getBeanClassName() + "]");
        }
        else if (count == 1) {
            // Mark override as not overloaded, to avoid the overhead of arg type checking.
            mo.setOverloaded(false);
        }
    }

步驟3- 實(shí)例化前的的后處理

doCreateBean()方法之前調(diào)用了resolveBeforeInstantiation方法對(duì)BeanDefinition中的屬性進(jìn)行前置處理。

  1. 調(diào)用實(shí)例化前處理器進(jìn)行處理。

  2. 短路判斷:如果前置處理返回的結(jié)果不為空,則直接略過后續(xù)Bean的創(chuàng)建而直接返回結(jié)果,這一特性至關(guān)重要,AOP功能就是基于這里的判斷的,如果不為空則調(diào)用初始化后處理器。

實(shí)例化的前置處理
beans.factory.support.AbstractAutowireCapableBeanFactory
    /**
     * Apply before-instantiation post-processors, resolving whether there is a
     * before-instantiation shortcut for the specified bean.
     * @param beanName the name of the bean
     * @param mbd the bean definition for the bean
     * @return the shortcut-determined bean instance, or {@code null} if none
     */
    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 = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }

4.2.1 初始化前的后處理器
    /**
     * Apply InstantiationAwareBeanPostProcessors to the specified bean definition
     * (by class and name), invoking their {@code postProcessBeforeInstantiation} methods.
     * <p>Any returned object will be used as the bean instead of actually instantiating
     * the target bean. A {@code null} return value from the post-processor will
     * result in the target bean being instantiated.
     * @param beanClass the class of the bean to be instantiated
     * @param beanName the name of the bean
     * @return the bean object to use instead of a default instance of the target bean, or {@code null}
     * @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
     */
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }
4.2.2 實(shí)例化后的后處理器
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessAfterInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }

實(shí)例化前的后處理器的應(yīng)用

將AbstractBeanDefinition轉(zhuǎn)換為BeanWrapper前的處理,給子類一個(gè)修改BeanDefinition的機(jī)會(huì),也就是說當(dāng)程序經(jīng)過這個(gè)方法之后,bean可能已經(jīng)不是我們認(rèn)為的bean了,而是或許成為一個(gè)經(jīng)過處理的代理bean,可能是通過cglib生成的,也可能是通過其他技術(shù)生成的,會(huì)在AOP中進(jìn)行講解,需要清楚的是在bean的實(shí)例化前會(huì)調(diào)用后處理器的方法進(jìn)行處理。

初始化后的后處理器

Spring保證bean初始化后盡可能將注冊(cè)的后處理器postProcessAfterInitialization方法應(yīng)用到該bean中。

步驟4- doCreateBean方法詳解

Spring-IOC-循環(huán)依賴檢測與Bean的創(chuàng)建

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,527評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,261評(píng)論 6 342
  • Spring容器高層視圖 Spring 啟動(dòng)時(shí)讀取應(yīng)用程序提供的Bean配置信息,并在Spring容器中生成一份相...
    Theriseof閱讀 2,915評(píng)論 1 24
  • 我的第一份工作很不如意。 換工作時(shí),我準(zhǔn)備了6個(gè)月的生活費(fèi),打算長期抗戰(zhàn)。但沒料到,投完簡歷不到一星期,就被叫去面...
    越女事務(wù)所閱讀 222評(píng)論 0 0
  • 前兩天的豆瓣評(píng)分報(bào)告出來了,我的2015年標(biāo)記了200+的電影(雖然有些事很久之前看的,隨手記上了) 發(fā)現(xiàn)了自己看...
    獨(dú)行向日葵閱讀 233評(píng)論 1 0

友情鏈接更多精彩內(nèi)容