Spring4.3.x 容器中bean的創建過程(4)—— 執行bean的初始化方法

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/chyohn/article/details/54967906

概述

Spring4.3.x 容器中bean的創建過程(1)——走進初始化bean的主要戰場一篇中我們找到了初始化bean的主要場所在AbstractAutowireCapableBeanFactory類中的doCreateBean方法中,在這個方法中首先調用createBeanInstance方法創建bean的實例;然後調用populateBean方法設置bean的屬性;接着調用initializeBean方法執行Bean後處理器和InitializingBean對象的afterPropertiesSet方法以及init-method方法;最後調用registerDisposableBeanIfNecessary方法註冊bean的銷燬方法。它的每一步都比較繁瑣,所以我把他們分開來探討。在 Spring4.3.x 容器中bean的創建過程(2)——實例化Bean一篇中,已經探討了第一步實例化bean。在 Spring4.3.x 容器中bean的創建過程(3)—— 初始化bean的屬性值 中探討了通過BeanWrapper對象設置bean的屬性。這一篇則探討最後一步——執行初始化方法並結束bean的創建。

執行bean的初始化方法

AbstractAutowireCapableBeanFactory類中的doCreateBean方法調用它的initializeBean方法來執行與bean初始化相關的各種初始化方法,initializeBean方法的源碼如下。

    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        // 首先執行Aware接口的方法
        // 這裏涉及的Aware接口有BeanFactoryAware、BeanClassLoaderAware和BeanNameAware
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }
            }, getAccessControlContext());
        } else {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 執行bean後處理器的postProcessBeforeInitialization方法
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // 執行實現自InitializingBean接口的afterPropertiesSet()方法
            // 執行bean的init-method方法
            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()) {
            // 執行bean後處理器的postProcessAfterInitialization方法
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }

如果bean實現了BeanFactoryAware、BeanClassLoaderAware或者BeanNameAware接口,initializeBean方法首先執行這些接口相應的方法,以確保後面的操作能夠拿到相應的對象,比如BeanFactory對象。接下來在執行bean的自身的初始化方法之前,則會執行bean後處理器的postProcessBeforeInitialization方法;在執行bean的自身的初始化方法之後,會執行bean後處理器的postProcessAfterInitialization方法。下面我們分別看看這4個方面的源碼。

(1)執行Aware接口的方法

initializeBean方法調用AbstractAutowireCapableBeanFactory類的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);
            }
        }
    }

在invokeAwareMethods方法中,我們只看到BeanFactoryAware、BeanClassLoaderAware和BeanNameAware三個接口的執行,Spring中還有其他Aware接口(比如ApplicationContextAware、ResourceLoaderAware、EnvironmentAware等)沒有得到執行。在Spring中,其他Aware接口在bean後處理器中執行,比如ApplicationContextAware、ResourceLoaderAware和EnvironmentAware會被ApplicationContextAwareProcessor後處理器處理,這個ApplicationContextAwareProcessor會在bean工廠創建後被添加到容器中。

(2)執行bean後處理器的postProcessBeforeInitialization方法

initializeBean方法調用AbstractAutowireCapableBeanFactory類的applyBeanPostProcessorsBeforeInitialization方法來發起post方法的執行,源碼如下。

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

在applyBeanPostProcessorsBeforeInitialization方法中,只要post方法返回結果爲null,則終止其他bean後處理的執行。在這裏我們看看ApplicationContextAwareProcessor後處理器的postProcessBeforeInitialization方法源碼,如下。

    @Override
    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(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    invokeAwareInterfaces(bean);
                    return null;
                }
            }, acc);
        } else {
            // 執行Aware接口
            invokeAwareInterfaces(bean);
        }

        return bean;
    }

    /**執行Aware接口**/
    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);
            }
        }
    }

(3)執行bean的初始化方法

initializeBean方法調用AbstractAutowireCapableBeanFactory類的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>() {
                        @Override
                        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);
            }
        }
    }

從invokeInitMethods方法中,首先執行InitializingBean接口的afterPropertiesSet方法,然後調用invokeCustomInitMethod方法執行自定義的初始化方法。下面是invokeCustomInitMethod方法的源碼。

    protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
        String initMethodName = mbd.getInitMethodName();
        // 檢查是否不在乎初始化方法是否是public的
        final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
                BeanUtils.findMethod(bean.getClass(), initMethodName) :
                ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
        if (initMethod == null) {
            if (mbd.isEnforceInitMethod()) {
                throw new BeanDefinitionValidationException("Couldn't find an init method named '" +
                        initMethodName + "' on bean with name '" + beanName + "'");
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug("No default init method named '" + initMethodName +
                            "' found on bean with name '" + beanName + "'");
                }
                // Ignore non-existent default lifecycle methods.
                return;
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Invoking init method  '" + initMethodName + "' on bean with name '" + beanName + "'");
        }

        // 執行初始化操作
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                @Override
                public Object run() throws Exception {
                    ReflectionUtils.makeAccessible(initMethod);
                    return null;
                }
            });
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    @Override
                    public Object run() throws Exception {
                        initMethod.invoke(bean);
                        return null;
                    }
                }, getAccessControlContext());
            } catch (PrivilegedActionException pae) {
                InvocationTargetException ex = (InvocationTargetException) pae.getException();
                throw ex.getTargetException();
            }
        } else {
            try {
                ReflectionUtils.makeAccessible(initMethod);
                initMethod.invoke(bean);
            } catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }

invokeCustomInitMethod方法的作用是,根據方法名稱獲取自定義的初始化方法,然後執行bean初始化方法。

(4)執行bean後處理器的postProcessAfterInitialization方法

initializeBean方法調用AbstractAutowireCapableBeanFactory類的applyBeanPostProcessorsAfterInitialization方法來發起post方法的執行,源碼如下。

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

在applyBeanPostProcessorsAfterInitialization方法中,只要post方法返回結果爲null,則終止其他bean後處理的執行。

總結

在執行bean完成屬性設置後執行初始化方法的過程中,Spring對bean的初始化操作提供了提供瞭如下擴展點。

(1)Spring提供了各種XxxAware接口,以在初始化的時候向bean注入當前容器擁有的Xxx對象,比如BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware、EnvironmentAware等。

(2)Spring提供了BeanPostProcessor接口,可以在執行bean自身的初始化方法前後執行相應的post方法。

(3)Spring提供了InitializingBean接口,可以在bean中實現這個接口的afterPropertiesSet()方法作爲初始化方法。

(4)在xml文件中配置init-method屬性或者在java代碼中使用@PostConstruct指定初始化方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章