Spring源碼分析之Bean的加載

作者: 一字馬胡
轉(zhuǎn)載標志 【2017-12-29】

更新日志

日期 更新內(nèi)容 備注
2017-12-29 創(chuàng)建分析文檔 Spring源碼分析系列文章(二)

前言

在Spring源碼分析的第一篇文章Spring源碼分析之Bean的解析中,主要梳理了Spring Bean解析的鏈路,當然只是梳理了主干部分,細節(jié)的內(nèi)容沒有涉及太多。本文接著上一篇文章,開始進行Spring Bean加載的源碼分析,bean解析完成之后,還不是可用的對象實例,需要進行加載,所謂bean的加載,就是將解析好的BeanDefinition變?yōu)榭捎玫腛bject。在進行源碼分析之前,可以猜測一下Spring bean加載到底做了些什么工作。首先,Spring bean解析的工作將我們在xml中配置的bean解析成BeanDefinition并且放在內(nèi)存中,現(xiàn)在,我們可以拿到每一個bean的完整的信息,其中最重要的應(yīng)該是Class信息,因為實例化對象需要知道具體需要實例化的Class信息。還需要知道具體bean的屬性值等信息,而這些數(shù)據(jù)目前都是可以拿到的,所以接下來的事情就是根據(jù)這些信息首先new一個對于Class類型的Object,然后進行一些初始化,然后返回。

當然,Spring bean加載的實現(xiàn)遠遠沒有這么簡單,這中間涉及的內(nèi)容很多,本文依然不會涉及太多細節(jié)的內(nèi)容,主要梳理Spring bean加載的主干流程,知道一個bean是如何被解析,以及如何加載的,是本文以及第一篇文章內(nèi)容所想要表達的內(nèi)容。

Spring Bean加載流程分析

分析Spring bean加載的第一步是找到分析的入口。接著上一篇文章的例子,從下面的代碼開始分析:


        String file = "applicationContext.xml";

        ApplicationContext context = new ClassPathXmlApplicationContext(file);

        ModelA modelA = (ModelA) context.getBean("modelA");

跟進context.getBean,可以在AbstractBeanFactory中找到具體的實現(xiàn):


    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

可以看到實際執(zhí)行的方法是doGetBean,因為這個方法較為復(fù)雜,所以拆開來分析實現(xiàn)的具體細節(jié)。首先關(guān)注下面的代碼:


    final String beanName = transformedBeanName(name);

    protected String transformedBeanName(String name) {
        return canonicalName(BeanFactoryUtils.transformedBeanName(name));
    }

    public static String transformedBeanName(String name) {
        Assert.notNull(name, "'name' must not be null");
        String beanName = name;
        while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
            beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
        }
        return beanName;
    }   

我們傳遞進去的name就是我們在xml中配置的id,首先會調(diào)用transformedBeanName對傳遞的name做一次處理,在transformedBeanName中又調(diào)用了BeanFactoryUtils.transformedBeanName方法來進行做處理,具體的內(nèi)容就是判斷我們傳遞的name是不是以“&”開頭的,要是的需要去掉再返回。需要注意的是,我們傳遞的name可能是bean的別名,也可能是BeanFactory,所以transformedBeanName的操作的目的就是取到真正的bean的名字,以便開始后續(xù)的流程。

獲取到bean的name之后,開始走下面的流程,需要注意下面的方法調(diào)用:


        // Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance = getSingleton(beanName);

具體的getSingleton的實現(xiàn)細節(jié)可以參考下面的代碼:

因為我們的bean在配置的時候可能會被配置為單例或者原型模式,單例模式的bean全局只會生成一次,所以getSingleton方法的目的是去Spring的單例bean緩存中尋找是否該bean已經(jīng)被初始化了,如果已經(jīng)被初始化了那么直接從緩存取到就可以了,就沒有必要走下面的流程了。上面貼出的getSingleton代碼實現(xiàn)的就是嘗試從緩存map中取bean,當然,這里面還是涉及一些其他的流程的。如果發(fā)現(xiàn)需要取的bean實例沒有在緩存中,那么就不能走緩存了,就需要走接下來的流程了。方法isSingletonCurrentlyInCreation實現(xiàn)的內(nèi)容是判斷當前bean是否是正在被加載的bean,判斷方法是使用一個set來實現(xiàn),沒當在進行加載單例bean之前,Spring會將該bean的name放到set中。earlySingletonObjects是一個map,存儲的是還沒有加載完成的bean的信息。如果發(fā)現(xiàn)從earlySingletonObjects中取到的bean實例為null的話,getSingleton方法就會進行該單例bean的加載。在實現(xiàn)上,首先通過取到用于創(chuàng)建該bean的BeanFactory,然后調(diào)用BeanFactory的getObject方法獲取到bean實例。

singletonFactories存儲著bean name以及創(chuàng)建該bean的BeanFactory。那用于獲取bean實例的BeanFactory是什么時候被什么對象放到map中來的呢?可以發(fā)現(xiàn)是一個叫做addSingletonFactory的方法在做這件事情,下面是這個方法的實現(xiàn)細節(jié):

那是什么地方調(diào)用該方法的呢?可以在AbstractAutowireCapableBeanFactory類中的doCreateBean方法中找到該方法的調(diào)用細節(jié),相關(guān)的上下文代碼如下:

接著回到getSingleton方法,獲取到用于創(chuàng)建bean實例的BeanFactory之后,就可以使用singletonFactory.getObject()來獲取到實例對象了。下面來分析一下這條鏈路的具體流程。這里需要注意一下,我們需要知道這個BeanFactory到底是什么樣的實現(xiàn),才能分析具體的內(nèi)容,所以解鈴還得系鈴人,回頭看看到底放到singletonFactories中的是一個什么樣的BeanFactory。最后發(fā)現(xiàn),實際執(zhí)行的方法是getEarlyBeanReference,見下面的代碼:


    /**
     * Obtain a reference for early access to the specified bean,
     * typically for the purpose of resolving a circular reference.
     * @param beanName the name of the bean (for error handling purposes)
     * @param mbd the merged bean definition for the bean
     * @param bean the raw bean instance
     * @return the object to expose as bean reference
     */
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

實際上我們需要關(guān)心的是第三個參數(shù)bean,這也就是實際的bean實例對象,那這個bean到底是什么呢?是怎么樣被創(chuàng)建出來的呢?這就得回頭看調(diào)用getEarlyBeanReference方法的上下文了,所以回頭看doCreateBean方法中的具體內(nèi)容。主要看下面這段代碼:

主要的流程是看緩存里面有沒有,如果有則不需要再次加載,否則需要調(diào)用方法createBeanInstance來創(chuàng)建bean實例,為了簡化問題,主要分析createBeanInstance這個方法的實現(xiàn)細節(jié)。首先調(diào)用方法resolveBeanClass獲取bean的Class,然后判斷權(quán)限等操作,首先來看instantiateBean方法的具體細節(jié),該方法代表使用默認構(gòu)造函數(shù)來進行bean的實例化,而autowireConstructor方法則代表使用有參數(shù)的構(gòu)造函數(shù)來進行bean的實例化。下面是instantiateBean的實現(xiàn)細節(jié):

主要關(guān)注:beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent)這一句代碼,然后看instantiate這個方法的實現(xiàn)細節(jié):

主要關(guān)注:return BeanUtils.instantiateClass(constructorToUse)這行代碼以及else分支的return語句,閑來看return BeanUtils.instantiateClass(constructorToUse)這句代碼的實現(xiàn)細節(jié):

其實就是根據(jù)類的構(gòu)造函數(shù)以及構(gòu)造函數(shù)參數(shù)來new一個對象,具體的細節(jié)可以再跟進去詳細研究。下面來看else分支中的instantiateWithMethodInjection(bd, beanName, owner),下面是具體的實現(xiàn)代碼:

具體的內(nèi)容就是使用CGlib來進行對象的創(chuàng)建,具體的內(nèi)容可以參考其他的資料,或者再跟下去來詳細研究。下面來看使用有參構(gòu)造函數(shù)來進行bean的實例化的具體實現(xiàn)細節(jié),對應(yīng)的方法是autowireConstructor,該方法相對于使用默認構(gòu)造函數(shù)來進行bean的實例化來說,需要做的事情是,因為bean可能有多個構(gòu)造函數(shù),并且可能權(quán)限不同,所以Spring需要根據(jù)參數(shù)個數(shù)以及類型選取一個合適的構(gòu)造函數(shù)來進行bean的實例化,這部分代碼較多,但是大概的流程就是這樣,代碼就不再貼出來了。

在new出來一個bean實例之后,還沒有真正完成Spring的bean加載內(nèi)容,因為除了new出來一個Object之外,還需要做其他的事情,下面來分析一下Spring都做了一些什么事情。首先是populateBean方法,該方法實現(xiàn)的功能是對bean進行屬性注入,下面是該方法的關(guān)鍵代碼:


        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }

            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }

            pvs = newPvs;
        }

autowireByName代表根據(jù)名字自動注入屬性,而autowireByType實現(xiàn)的是根據(jù)類型自動注入屬性,根據(jù)名字注入相對簡單一些,而根據(jù)類型注入要復(fù)雜很多,下面先來分析根據(jù)名字自動注入屬性的分析。下面是autowireByName的代碼:


    protected void autowireByName(
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
        for (String propertyName : propertyNames) {
            if (containsBean(propertyName)) {
                Object bean = getBean(propertyName);
                pvs.add(propertyName, bean);
                registerDependentBean(propertyName, beanName);
                if (logger.isDebugEnabled()) {
                    logger.debug("Added autowiring by name from bean name '" + beanName +
                            "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
                            "' by name: no matching bean found");
                }
            }
        }
    }

    /**
     * Return an array of non-simple bean properties that are unsatisfied.
     * These are probably unsatisfied references to other beans in the
     * factory. Does not include simple properties like primitives or Strings.
     * @param mbd the merged bean definition the bean was created with
     * @param bw the BeanWrapper the bean was created with
     * @return an array of bean property names
     * @see org.springframework.beans.BeanUtils#isSimpleProperty
     */
    protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
        Set<String> result = new TreeSet<>();
        PropertyValues pvs = mbd.getPropertyValues();
        PropertyDescriptor[] pds = bw.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
                    !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
                result.add(pd.getName());
            }
        }
        return StringUtils.toStringArray(result);
    }

unsatisfiedNonSimpleProperties方法首先獲取所有需要進行依賴注入的屬性名稱,然后保存起來,特別需要注意的是registerDependentBean這個方法的調(diào)用,該方法實現(xiàn)的是維護bean的依賴管理。接著是根據(jù)類型注入autowireByType的實現(xiàn)。該方法的實現(xiàn)還是很復(fù)雜的,暫時不對該方法進行分析。

當執(zhí)行完上面兩個方法之后,已經(jīng)獲取到了所有需要注入的屬性信息,pvs持有這些信息,接著,applyPropertyValues方法會實際將這些依賴注入。下面來分析一下applyPropertyValues方法的具體實現(xiàn)流程。具體的實現(xiàn)細節(jié)可以參考下面給出的索引:


AbstractAutowireCapableBeanFactory#applyPropertyValues


主要關(guān)注核心代碼:bw.setPropertyValues(mpvs),bw是bean實例對象,mpvs是屬性信息。如果再追蹤下去,就可以看到如下的代碼鏈路:


    public void setPropertyValues(PropertyValues pvs) throws BeansException {
        setPropertyValues(pvs, false, false);
    }

    public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
            throws BeansException {

        List<PropertyAccessException> propertyAccessExceptions = null;
        List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
                ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
        for (PropertyValue pv : propertyValues) {
            setPropertyValue(pv);
        }
    }
    

這里面已經(jīng)去掉了一些異常處理的代碼,只留下最核心的代碼,主要關(guān)注setPropertyValue這個方法,再繼續(xù)跟蹤下去:


    public void setPropertyValue(PropertyValue pv) throws BeansException {
        setPropertyValue(pv.getName(), pv.getValue());
    }


到這里就應(yīng)該很清晰了,pv.getName()是屬性名稱,而pv.getValue()就是實際上注入的依賴。在完成依賴注入之后,應(yīng)該說bean就可以使用了,但是因為Spring還提供了一些其他的標簽讓用戶進行個性化設(shè)置,比如初始化方法、銷毀方法等,接著看exposedObject = initializeBean(beanName, exposedObject, mbd)這行代碼的實際工作流程。


    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

這其中調(diào)用了幾個個性化的方法,第一個是invokeAwareMethods,是去訪問子類的Aware,BeanClassLoaderAware, BeanFactoryAware等,下面是該方法的實現(xiàn)細節(jié):


    private void invokeAwareMethods(final String beanName, final Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }

接著是applyBeanPostProcessorsBeforeInitialization方法,是訪問子類的后處理器內(nèi)容,下面是該方法的詳細實現(xiàn):


    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {

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

接著是invokeInitMethods方法,是調(diào)用用戶設(shè)定的init方法,下面是該方法的實現(xiàn)細節(jié):


protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {

        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

這其中需要注意的一點是,在該方法中調(diào)用了afterPropertiesSet方法,然后是獲取了用戶設(shè)定的init方法的名字,然后調(diào)用invokeCustomInitMethod方法執(zhí)行了這個init方法。

到此,單例bean的加載好像分析到頭了,確實是,當然這只是一個很小的分支,還有其他的分支沒有走,現(xiàn)在回到doGetBean方法,繼續(xù)分析剩下的代碼。為了分析簡單,直接從下面的代碼開始分析,其他沒有分析到的代碼以后再詳細分析,現(xiàn)在主要是希望走通整個流程,所以只會挑選關(guān)鍵的代碼進行分析。首先是下面的代碼:


                // Guarantee initialization of beans that the current bean depends on.
                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可能依賴其他的bean,所以需要在加載當前bean之前加載它所依賴的bean。所以這里面又調(diào)用了getBean方法來循環(huán)加載依賴的bean。接著看下面的代碼:

如果bean是一個單例bean,那么會走到該分支里面。會調(diào)用getSingleton方法來加載該bean。getSingleton方法的第一個參數(shù)是beanName,第二個參數(shù)比較關(guān)鍵,是用于創(chuàng)建bean的BeanFactory,所以有必要仔細分析一下該BeanFactory。因為在getSingleton方法中關(guān)鍵的步驟就是調(diào)用BeanFactory的getObject方法來獲取到一個bean的實例,當然還有很多其他的細節(jié)需要判斷,但不再本文的敘述范圍之內(nèi)。下面來看這個BeanFactory的具體實現(xiàn)。根據(jù)上面貼出的代碼,其實內(nèi)部關(guān)鍵調(diào)用了一個方法createBean。下面來看這個方法的實現(xiàn)細節(jié)。該方法的關(guān)鍵內(nèi)容如下:

首先會調(diào)用resolveBeforeInstantiation方法,這是一個試探性的方法調(diào)用,根據(jù)描述,該方法是給BeanPostProcessors一個機會來返回bean實例,具體看看該方法的細節(jié):


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

該方法關(guān)鍵會先調(diào)applyBeanPostProcessorsBeforeInstantiation方法來調(diào)用實現(xiàn)類的postProcessBeforeInstantiation方法,如果返回內(nèi)容還為null,就會繼續(xù)調(diào)用applyBeanPostProcessorsAfterInitialization方法來調(diào)用實現(xiàn)類的postProcessAfterInitialization。所以這里需要注意一下,這也是一個Spring使用技巧點,可以繼承BeanPostProcessor來實現(xiàn)個性化的Spring bean定制。

當resolveBeforeInstantiation方法返回null的時候,就會繼續(xù)調(diào)用doCreateBean方法來加載bean的實例。該方法中首先一個比較關(guān)鍵的方法調(diào)用是createBeanInstance,下面的流程在上文中已經(jīng)進行過了,就不再贅述了。只要知道doCreateBean方法返回的就是一個bean的實例就好了。

當然,我們獲取到的bean實例可能是一個FactoryBean,那么就需從FactoryBean中獲取到Object。實現(xiàn)該流程的是方法getObjectForBeanInstance。主要看該方法中調(diào)用的getObjectFromFactoryBean方法。進到getObjectFromFactoryBean方法之后主要注意方法doGetObjectFromFactoryBean。該方法的主要流程代碼如下:

主要關(guān)注代碼:object = factory.getObject(),繼續(xù)看下面的代碼:


    public final T getObject() throws Exception {
        if (isSingleton()) {
            return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());
        }
        else {
            return createInstance();
        }
    }

這里區(qū)分了單例和原型兩種bean,如果bean被配置為單例,則會走第一個分支,原型則會走第二個分支。對于單例bean,首先會判斷是否已經(jīng)初始化過了,如果已經(jīng)初始化過了,那么就直接取到bean實例,否則會調(diào)用getEarlySingletonInstance來獲取到bean的實例,下面來具體分析一下getEarlySingletonInstance這個方法的執(zhí)行流程。跟蹤進去最后執(zhí)行的代碼是下面的方法:


    private T getEarlySingletonInstance() throws Exception {
        Class<?>[] ifcs = getEarlySingletonInterfaces();
        if (ifcs == null) {
            throw new FactoryBeanNotInitializedException(
                    getClass().getName() + " does not support circular references");
        }
        if (this.earlySingletonInstance == null) {
            this.earlySingletonInstance = (T) Proxy.newProxyInstance(
                    this.beanClassLoader, ifcs, new EarlySingletonInvocationHandler());
        }
        return this.earlySingletonInstance;
    }

到這里就很清晰了,還是會判斷是否已經(jīng)加載過了,如果加載過了,那么就不會重復(fù)實例化bean了,否則就使用java的動態(tài)代理技術(shù)生成一個bean實例。

對于原型bean來說,會調(diào)用createInstance方法進行bean的實例化過程,對不同類型的FactoryBean會使用不同的子類的方法來獲取實例,比如AbstractFactoryBean的子類等等。

到這里需要說明一下FactoryBean這個類,F(xiàn)actoryBean是一個Bean,實現(xiàn)了FactoryBean接口的類有能力改變bean,F(xiàn)actoryBean希望你實現(xiàn)了它之后返回一些內(nèi)容,Spring會按照這些內(nèi)容
去注冊bean,這也給了程序員一個定制bean的機會,繼承了FactoryBean的子類的bean的加載會調(diào)用FactoryBean的getObject方法獲取bean實例,而且,我們使用getBean獲取到的是FactoryBean的getObject方法調(diào)用的結(jié)果,如果想要獲取到FactoryBean本身,需要在bean前面加上“&”標志,這個邏輯可以在方法getObjectForBeanInstance中找到:


        // Now we have the bean instance, which may be a normal bean or a FactoryBean.
        // If it's a FactoryBean, we use it to create a bean instance, unless the
        // caller actually wants a reference to the factory.
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }

如果對BeanFactory和FactoryBean傻傻分不清,可以參考文章Spring的BeanFactory和FactoryBean,主要思路就是看后綴,BeanFactory是一種FactoryBean,是用來生成bean的,而FactoryBean是一個bean,它是用來改變FactoryBean生成bean的路徑的。

需要注意的一點是,上文的分析中并沒有涉及緩存的內(nèi)容,這部分內(nèi)容比較離散,我們在走主流程的時候只要知道它會在何時的時候填充緩存(主要關(guān)注單例bean),以及在需要的時候從緩存中獲取就可以了。

接著回到doGetBean方法中,看下面的分支:

如果不是一個單例的話,那么可能是一個Prototype類型的bean,所謂Prototype類型的bean,就是每次都會創(chuàng)建一個bean實例,這是和單例區(qū)分開來說的,除此之外,和單例bean的加載沒有區(qū)別,所以也不再贅述了。

doGetBean方法還有后續(xù)的流程沒有走完,但是到此為止我們已經(jīng)明白了一個bean是如何被加載的,它現(xiàn)在幾乎可以被使用了,后面就是一些收尾工作,具體流程就不再分析了,后續(xù)會進行一些策略性的補充。

本文涉及的內(nèi)容時Spring bean的加載,內(nèi)容較多,而且較為復(fù)雜,很多內(nèi)容都沒有提及,只是大概梳理了一下主干流程,接著上一篇文章來繼續(xù)分析,在上一篇文章中分析了Spring bean解析的流程,解析完成之后需要加載才能使用,在加載的過程中設(shè)計很多內(nèi)容,其中包括bean的實例化,以及bean的依賴注入等內(nèi)容。bean的加載大體上分為單例和原型,本文主要分析了單例bean的加載,原型bean的加載與單例bean的加載流程是一樣的,只是單例全局只有一個bean實例,所有可以從緩存中取到,而原型bean每次都是新創(chuàng)建一個bean實例??傮w來講,分析Spring的源碼還是比較復(fù)雜的,本文中欠缺的內(nèi)容將在未來陸續(xù)補充完善,但主要目的還是梳理流程,走一遍Spring容器的方方面面,這樣使用起來就會多幾分底氣了。

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

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

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