spring bean的裝載過程簡略賞析


spring一個bean的容器,它從這個最基本的功能進而擴展出AOP,transaction,cache,schedule,data等等,將業務與框架代碼解耦,讓我們可以將大部分精力投入到業務代碼中,這是一個偉大的開源項目,帶着這份感激與贊美之情,來看一spring最基本的功能--bean的裝載:

  我們知道,spring在1與2時使用xml等配置文件來配置bean的聲明,而3以后,spring則引入注解,大大簡化了bean的繁雜的配置,bean的裝載部分並沒有發生本質上的變化,只是稍稍做了一些改動。

  如何讀取bean,這部分在本篇不打算詳細介紹。簡單說明一下流程:spring獲取bean信息(具體是配置文件還是注解按具體場景決定),將bean信息賦予BeanDefifition,這個類是關鍵,它承載了bean的所有信息。

  在拿到BeanDefinition后,spring便開始裝載之旅,spring將bean的裝載划分為幾個步驟:1.裝載前,2.賦值前,3.賦值后.4.裝載后,基於這些步驟,spring均預留了相應的接口,供外部邏輯參與到bean的裝載過程中.

首先看下AbstractAutowireCapableBeanFactory.java的doCreateBean方法

    // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                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);
            }
        }

主要看上面這部分代碼,一個是populateBean,一個是initializeBean,這兩個方法完成了bean的賦值與初始化。先看populateBean:

// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        boolean continueWithPropertyPopulation = true;

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }

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

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

        if (hasInstAwareBpps || needsDepCheck) {
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }

        applyPropertyValues(beanName, mbd, bw, pvs);

populateBean做了這樣幾件事情:調用實現了InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation方法,確認bean的賦值是否繼續,調用postProcessPropertyValues方法來確保依賴已經解析完畢,並且可以替換property的value.做完這些操作后,就可以開始賦值了.

  到此,我們發現並沒有發生真正的賦值,真正的賦值邏輯在 applyPropertyValuesf方法中:

if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            if (mpvs.isConverted()) {
                // Shortcut: use the pre-converted values as-is.
                try {
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
                }
            }
            original = mpvs.getPropertyValueList();
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

        // Create a deep copy, resolving any references for values.
        List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
                }
                // Possibly store converted value in merged bean definition,
                // in order to avoid re-conversion for every created bean instance.
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // Set our (possibly massaged) deep copy.
        try {
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }

這里有一個BeanDefinitionValueResolver,這個類用來解析property里的value,如果是依賴其他bean則會到容器中找是否存在如果有則返回,沒有則創建一個。spring又為每個對象的屬性定義了一個數據結構:PropertyValue,這樣做加大了容器對bean屬性的修改的靈活性,上面的方法就是對每個屬性進行處理然后通過beanWapper的setPropertyValues進行賦值。

這里注意一下,bean有singleton和prototype兩種 ,對於prototype,spring采用了原型模式,使用對象的deepcopy。

至此,spring完成了對實例的賦值,然后就是調用initializeBean:

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    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;
    }

這里有四個重要的方法.

invokeAwareMethods
applyBeanPostProcessorsBeforeInitialization
invokeInitMethods
applyBeanPostProcessorsAfterInitialization

使用spring,就一定會知道spring有一系列aware,比如(beanNameAware,beanFactoryAware,aplicationContextArware,enviromentAware等等)。這些aware使得代碼與spring框架耦合,帶來的好處就是能讓代碼使用spring框架提供的強大功能,我們看到,在initializeBean方法中,一開始就調用了invokeAwareMethods:

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) {
                ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
            }
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }

這些aware發生在對象被賦值以后,在bean創建的過程中我們只看到了被調用的3個Aware方法,事實上這3個Aware方法我們用的並不多,這是因為我們常用的容器實際上是更上層的applicationContext,那么applicationContext容器的aware實在何時被調用的呢,我們會在下面的講解中展示給大家.

接下來,調用了applyBeanPostProcessorsBeforeInitialization方法:

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

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

我們看到,這里開始調用所有注冊了BeanPostProcessor的postProcessBeforeInitialization方法,這個方法的實現類列表中,我們看到了aop的身影,aop就是從這里開始參與進來的。

前面提到過applicationContext級別的Awaref方法的調用,沒錯,就是在這里.看一下這個類:ApplicationContextAwareProcessor它實現了BeanPostProcessor接口

這個是專門處理ApplicationContextAware相關的接口的調用的:

public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean);
                return null;
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }

        return bean;
    }
private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

這個類會在spring的refresh方法被調用的時候被創建出來,至於refresh方法何時被調用就不是本篇的重點了

上面說過,還有一個重要的方法:invokeInitMethods,從字面上可以看出,這是調用bean的初始化方法

protected void invokeInitMethods(String beanName, final Object bean, 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(new PrivilegedExceptionAction<Object>() {
                        public Object run() throws Exception {
                            ((InitializingBean) bean).afterPropertiesSet();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }                
            else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

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

看了這個實現,發現,原來偉大的spring也會在代碼里存在硬編碼,沒錯,這就是調用實現了InitializingBean的類的afterPropertiesSet方法,只不過之前做了一系列校驗

最后再調用applyBeanPostProcessorsAfterInitialization方法,同樣上面一樣,循環遍歷調用注冊了beanPostProcessor的方法,最后返回一個處理完成的bean實例,注意了,spring aop就是在此介入的,有興趣的同學可以看一下我的另一篇博客spring @EnableAspectJAutoProxy背后的那些事(spring AOP源碼賞析),至此,一個完成的bean的裝載過程已經完成。

    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

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

 

總結一下,我們經常用到的(可能用到的)一些f方法被調用的順序:

beanFactoryArware這是最底層的了

EnvironmentAware
ResourceLoaderAware
ApplicationEventPublisherAware
ApplicationContextAware
afterPropertiesSet
 
 

 

以上是我個人理解,因技術尚有不足,理解有誤地方還望大家指正,多多交流,謝謝!                                                                                                                                                                                                                                                               轉載請注明出處!


免責聲明!

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



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