[Spring]Spring的getBean路線-createBean

前言

承上啟下:

  1. Spring的refresh->finishBeanFactoryInitialization(容器初始化單例非延遲加載Bean的入口).
  2. beanFactory.preInstantiateSingletons();,Bean工廠開始加載Bean實(shí)例.
  3. 獲取beanName列表,循環(huán)對每個(gè)beanName進(jìn)行getBean操作.
  4. getBean中調(diào)用了doGetBean進(jìn)行了一些創(chuàng)建Bean的前置處理.最終在getSingleton中調(diào)用了createBean進(jìn)行Bean的創(chuàng)建.

OK,下面進(jìn)入今天的主題-createBean.

createBean的總體流程

  • 解析Bean類型,獲取Class: resolveBeanClass.
  • 檢查和準(zhǔn)備Bean中的方法覆蓋: prepareMethodOverrides.
  • 應(yīng)用實(shí)例化之前的后處理器: resolveBeforeInstantiation.
  • 開始創(chuàng)建Bean: doCreateBean

1. resolveBeanClass-解析Bean類型,獲取Bean的Class.

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

        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // 確認(rèn)當(dāng)前的Bean類是可以被解析的,并且支持克隆BeanDefinition,merged的BeanDefinition不在此方法的考慮范圍
        // 進(jìn)入到里面,會發(fā)現(xiàn)器通過了類加載器進(jìn)行了Class的獲取
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            // 克隆一份BeanDefinition,用來設(shè)置上加載出來的對象
            // 采用副本的原因是某些類可能需要?jiǎng)討B(tài)加載Class
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }
        // 省略若干代碼
}

容器在前面已經(jīng)加載并注冊好了BeanDefinition,它描述了關(guān)于Bean的信息,在此處Spring要開始將自己抽象出來的BeanDefinition進(jìn)行解析.這里思考一個(gè)問題,為什么Spring在加載Bean的時(shí)候選擇了RootBeanDefinition進(jìn)行解析,而不是之前在加載BeanDefinition的時(shí)候反復(fù)說到的GenericBeanDefinition?

RootBeanDefinition對應(yīng)的是Java中的繼承體系而制造的復(fù)合BeanDefinition(Spring在定義Bean時(shí),也支持定義繼承關(guān)系).從各種容器加載出來的BeanDefinition,最終都會通過getMergedLocalBeanDefinition轉(zhuǎn)化成RootBeanDefinition.

RootBeanDefinition可以合成有繼承關(guān)系的BeanDefinition(如果沒有繼承關(guān)系,那么自己便是代表parent).

這里推薦一篇文章,希望可以帶來更多的思考: 【小家Spring】Spring IoC容器中核心定義之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...)

OK,回到主題,拿到傳進(jìn)來的RootBeanDefinition后,Spring需要確認(rèn)當(dāng)前的Bean類是可以被解析的,即是否能通過類加載器進(jìn)行載入.對于注解容器來說,在組件掃描的時(shí)候就通過ResourceLoader進(jìn)行了資源的定位,所以在這里是可以確認(rèn)可以被解析的.
考慮到健全性,Spring還是謹(jǐn)慎地進(jìn)行了校驗(yàn),畢竟不是所有的BeanDefinition都是通過注解容器加載的.

  • AbstractBeanFactory#resolveBeanClass
    protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
            throws CannotLoadBeanClassException {

        try {
            // 如果當(dāng)前BeanDefinition存儲beanClass屬于Class實(shí)例,直接返回
            if (mbd.hasBeanClass()) {
                return mbd.getBeanClass();
            }
            if (System.getSecurityManager() != null) {
                return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)
                        () -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
            }
            else {
                // 如果當(dāng)前BeanDefinition沒有存儲Class實(shí)例,那么嘗試解析
                return doResolveBeanClass(mbd, typesToMatch);
            }
        }
        catch (PrivilegedActionException pae) {
            ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }
        catch (ClassNotFoundException ex) {
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }
        catch (LinkageError err) {
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
        }
    }
  • AbstractBeanFactory#doResolveBeanClass
    private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
            throws ClassNotFoundException {

        ClassLoader beanClassLoader = getBeanClassLoader();
        ClassLoader dynamicLoader = beanClassLoader;
        boolean freshResolve = false;

        if (!ObjectUtils.isEmpty(typesToMatch)) {
            // When just doing type checks (i.e. not creating an actual instance yet),
            // use the specified temporary class loader (e.g. in a weaving scenario).
            ClassLoader tempClassLoader = getTempClassLoader();
            if (tempClassLoader != null) {
                dynamicLoader = tempClassLoader;
                freshResolve = true;
                if (tempClassLoader instanceof DecoratingClassLoader) {
                    DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                    for (Class<?> typeToMatch : typesToMatch) {
                        dcl.excludeClass(typeToMatch.getName());
                    }
                }
            }
        }
        // 獲取BeanDefinition的className.
        String className = mbd.getBeanClassName();
        if (className != null) {
            // 根據(jù)className解析成表達(dá)式
            Object evaluated = evaluateBeanDefinitionString(className, mbd);
            if (!className.equals(evaluated)) {
                // A dynamically resolved expression, supported as of 4.2...
                if (evaluated instanceof Class) {
                    return (Class<?>) evaluated;
                }
                else if (evaluated instanceof String) {
                    className = (String) evaluated;
                    freshResolve = true;
                }
                else {
                    throw new IllegalStateException("Invalid class name expression result: " + evaluated);
                }
            }
            if (freshResolve) {
                // When resolving against a temporary class loader, exit early in order
                // to avoid storing the resolved Class in the bean definition.
                if (dynamicLoader != null) {
                    try {
                        // 如果解析后的表達(dá)式為Class則直接返回
                        return dynamicLoader.loadClass(className);
                    }
                    catch (ClassNotFoundException ex) {
                        if (logger.isTraceEnabled()) {
                            logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
                        }
                    }
                }
                // 反射工具類加載Class
                return ClassUtils.forName(className, dynamicLoader);
            }
        }

        // Resolve regularly, caching the result in the BeanDefinition...
        return mbd.resolveBeanClass(beanClassLoader);
    }

這里Spring會獲取到當(dāng)前工廠的類加載器,然后從BeanDefinition中獲取className.Spring會先對className做表達(dá)式解析,如果不是通過表達(dá)式進(jìn)行解析,那么調(diào)用ClassUtils.forName(className, dynamicLoader);,如果className不存在,再使用類加載器進(jìn)行加載.類于類加載器是一一對應(yīng)的關(guān)系,Spring需要找到可以加載該類的類加載器,然后加載出Class對象.

2. 檢查和準(zhǔn)備Bean中的方法覆蓋-prepareMethodOverrides

  • AbstractAutowireCapableBeanFactory#createBean
        // Prepare method overrides.
        // 檢查和準(zhǔn)備Bean中的方法覆蓋
        try {
            mbdToUse.prepareMethodOverrides();
        }
  • AbstractBeanDefinition#prepareMethodOverrides

主要針對lookup methods做校驗(yàn)和方法覆蓋?,F(xiàn)在用得比較少了.
如果對Lookup方法注入有興趣,可以在Spring的官網(wǎng)查看: 點(diǎn)我前往

  • AbstractBeanDefinition#prepareMethodOverrides
    public void prepareMethodOverrides() throws BeanDefinitionValidationException {
        // Check that lookup methods exist and determine their overloaded status.
        // 檢查查找方法是否存在,并確定其重載狀態(tài)。
        if (hasMethodOverrides()) {
            getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
        }
    }
  • AbstractBeanDefinition#prepareMethodOverride

驗(yàn)證并準(zhǔn)備給定的方法是否被重寫。檢查是否存在具有指定名稱的方法,如果找不到該方法,則將其標(biāo)記為未重載。

    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() + "]");
        }
        // 如果不存在重載,在使用CGLIB增強(qiáng)階段就不需要校驗(yàn)了
        else if (count == 1) {
            // Mark override as not overloaded, to avoid the overhead of arg type checking.
            // 將替代標(biāo)記為未過載,以避免arg類型檢查的開銷。
            mo.setOverloaded(false);
        }
    }

3. 激活Bean實(shí)例化前的后置處理器-resolveBeforeInstantiation

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            // 解析BeanPostProcessors的BeanPostProcessorsBeforeInstantiation,試圖返回一個(gè)需要?jiǎng)?chuàng)建Bean的代理對象
            // resolveBeforeInstantiation只針對有自定義的targetsource.
            // 因?yàn)樽远x的targetsource不是Spring的bean,那么后續(xù)的初始化與該bean無關(guān)
            // 因此直接可以進(jìn)行代理
            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);
        }
  • AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        // 如果beforeInstantiationResolved為false
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            // 如果注冊了InstantiationAwareBeanPostProcessors的BeanPostProcessor.
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {
                    // 執(zhí)行實(shí)現(xiàn)了該后置處理器接口的類中postProcessBeforeInitialization方法
                    // Spring在這里使用了責(zé)任鏈模式,如果有一個(gè)后置處理器可以返回Object,就會馬上跳出循環(huán)
                    // 同時(shí),如果第三方框架在此后置處理器對Bean執(zhí)行了操作,那么將不會進(jìn)入到doCreateBean中了.
                    // 注意傳參,這里傳入的是一個(gè)class和beanName.
                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }

如果當(dāng)前的Bean實(shí)現(xiàn)了InstantiationAwareBeanPostProcessor接口,并且在postProcessBeforeInstantiation中返回了Object,那么Spring將不會執(zhí)行doCreateBean進(jìn)行實(shí)例化,而是將當(dāng)前用戶返回的bean實(shí)例直接返回。
AbstractAutoProxyCreator這個(gè)AOP代理的BeanPostProcessor便是這樣做的.
執(zhí)行完before的操作后,如果返回了實(shí)例,那么繼續(xù)執(zhí)行after的操作.
其中,before和after的執(zhí)行邏輯有點(diǎn)區(qū)別:
before方法執(zhí)行的中斷條件:

                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }

after方法執(zhí)行的中斷條件:

            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }

關(guān)注這個(gè)BeanPostPorcessor,在后續(xù)的學(xué)習(xí)中,我們?nèi)阅茉谶^濾器中學(xué)習(xí)到這種職責(zé)鏈的設(shè)計(jì)原則.
我們來看看InstantiationAwareBeanPostProcessor的接口清單.默認(rèn)返回null.

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    @Nullable
    default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }
}

4. 開始創(chuàng)建Bean-doCreateBean

OK,再梳理一下思路,從createBean中,Spring分析了當(dāng)前的Class是否能被類加載器加載,如果可以加載,返回當(dāng)前BeanDefinitino的Class對象,接著進(jìn)行了Lookup method的檢查,最后激活了InstantiationAwareBeanPostProcessors的方法,如果以上方法都沒中斷,那么Spring將進(jìn)行Bean的實(shí)例化-doCreateBean.

        try {
            // 創(chuàng)建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);
        }

總結(jié)

  • 在createBean階段,Spring會分析當(dāng)前BeanDefinition的Class是否是可解析的.具體表現(xiàn)為用類加載器進(jìn)行l(wèi)oadClass或者Class.forName
  • 檢查當(dāng)前BeanDefinition的Lookup method是否存在,并且確認(rèn)重載狀態(tài).
  • 如果實(shí)現(xiàn)了InstantiationAwareBeanPostProcessors,激活此后置處理器,如果可以從此后置處理器中獲取Bean實(shí)例,那么直接返回該Bean實(shí)例,不會進(jìn)行doCreateBean操作.
  • 開始Bean的實(shí)例化-doCreateBean.

doCreateBean篇幅較長,將拆分幾篇文章進(jìn)行講解,如果覺得不錯(cuò),請關(guān)注我的博客~

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

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

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