Spring4.3.x 容器中bean的創建過程(5)—— 註冊bean的銷燬方法

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

概述

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的屬性。在 Spring4.3.x 容器中bean的創建過程(4)—— 執行bean的初始化方法一篇探討了Spring如何執行bean初始化方法。這一篇探討bean創建過程中的最後一步——註冊bean的銷燬方法。

註冊bean的銷燬方法

AbstractAutowireCapableBeanFactory類中的doCreateBean方法調用它的registerDisposableBeanIfNecessary方法來執行與註冊bean的銷燬方法的操作,registerDisposableBeanIfNecessary方法的源碼如下。

    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
        AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
        // 檢測bean是否需要註冊消費方法
        if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
            if (mbd.isSingleton()) {
                // 註冊單例bean的銷燬方法
                registerDisposableBean(beanName,
                        new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
            } else {
                // 自定義的作用域
                Scope scope = this.scopes.get(mbd.getScope());
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
                }
                // 在自定義作用域小注冊銷燬方法
                scope.registerDestructionCallback(beanName,
                        new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
            }
        }
    }

對於作用域爲prototype的,Spring不會爲其註冊銷燬方法。另外registerDisposableBeanIfNecessary方法還會調用requiresDestruction方法檢測bean是否需要註冊銷燬方法。如果bean需要註冊消費方法,registerDisposableBeanIfNecessary把進一步根據作用域把bean分成兩類,一類是singleton作用域的bean,另一類是自定義作用域的bean。

(1)檢測bean是否需要註冊銷燬方法

registerDisposableBeanIfNecessary方法還會調用AbstractAutowireCapableBeanFactory類的requiresDestruction方法檢測bean是否需要註冊銷燬方法。requiresDestruction方法的源碼如下。

    protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
        return (bean != null &&
                (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&
                        DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
    }

在requiresDestruction方法中,判斷bean是否需要註冊銷燬方法,只需要滿足以下兩個條件之一。
a. 配置bean的時候,從bean的方法中選擇了一個銷燬方法
b. 容器中註冊了能夠處理被檢測bean並實現了DestructionAwareBeanPostProcessor接口的bean後處理器。

a. requiresDestruction方法調用DisposableBeanAdapter的hasDestroyMethod方法判斷bean是否有銷燬方法,hasDestroyMethod方法源碼如下。

    public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
        // 檢測bean是否實現了DisposableBean接口
        // JDK1.7以上版本的,檢測bean是否實現了AutoCloseable接口
        if (bean instanceof DisposableBean || closeableInterface.isInstance(bean)) {
            return true;
        }

        // 獲取配置的銷燬方法
        String destroyMethodName = beanDefinition.getDestroyMethodName();
        // 定義有public static final String INFER_METHOD = "(inferred)";
        if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
            // 定義有CLOSE_METHOD_NAME = "close"
            // 定義有SHUTDOWN_METHOD_NAME = "shutdown"
            return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
                    ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
        }
        return StringUtils.hasLength(destroyMethodName);
    }

b. requiresDestruction方法調用DisposableBeanAdapter的hasApplicableProcessors方法判斷是否有bean後處理器來處理bean的銷燬,hasApplicableProcessors方法的源碼如下。

    public static boolean hasApplicableProcessors(Object bean, List<BeanPostProcessor> postProcessors) {
        if (!CollectionUtils.isEmpty(postProcessors)) {
            for (BeanPostProcessor processor : postProcessors) {
                if (processor instanceof DestructionAwareBeanPostProcessor) {
                    DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
                    try {
                        if (dabpp.requiresDestruction(bean)) {
                            return true;
                        }
                    } catch (AbstractMethodError err) {
                        // Spring4.3之前版本的第三方DestructionAwareBeanPostProcessor
                        return true;
                    }
                }
            }
        }
        return false;
    }

(2)爲singleton的bean註冊銷燬方法

registerDisposableBeanIfNecessary方法還會調用AbstractAutowireCapableBeanFactory類的registerDisposableBean方法檢測bean是否需要註冊銷燬方法。registerDisposableBean方法的源碼如下。

    public void registerDisposableBean(String beanName, DisposableBean bean) {
        synchronized (this.disposableBeans) {
            this.disposableBeans.put(beanName, bean);
        }
    }

(3)爲自定義作用域的bean註冊銷燬方法

registerDisposableBeanIfNecessary方法還會調用Scope 對象的registerDestructionCallback方法檢測bean是否需要註冊銷燬方法。這裏我們以作用域爲request爲例,request作用域的處理類爲RequestScope,它的registerDestructionCallback方法繼承自AbstractRequestAttributesScope抽象類,的源碼如下。

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
        attributes.registerDestructionCallback(name, callback, getScope());
    }

下面是ServletRequestAttributes類實現的registerDestructionCallback方法

    @Override
    public void registerDestructionCallback(String name, Runnable callback, int scope) {
        if (scope == SCOPE_REQUEST) {
            // 註冊request作用域的銷燬方法
            registerRequestDestructionCallback(name, callback);
        } else {
            // 註冊session作用域的銷燬方法
            registerSessionDestructionCallback(name, callback);
        }
    }

下面的代碼是註冊request作用域的銷燬方法的源碼。

    protected final void registerRequestDestructionCallback(String name, Runnable callback) {
        Assert.notNull(name, "Name must not be null");
        Assert.notNull(callback, "Callback must not be null");
        synchronized (this.requestDestructionCallbacks) {
            this.requestDestructionCallbacks.put(name, callback);
        }
    }

下面的代碼是註冊session作用域的銷燬方法的源碼。


    public static final String DESTRUCTION_CALLBACK_NAME_PREFIX =
            ServletRequestAttributes.class.getName() + ".DESTRUCTION_CALLBACK.";

    protected void registerSessionDestructionCallback(String name, Runnable callback) {
        HttpSession session = getSession(true);
        session.setAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name,
                new DestructionCallbackBindingListener(callback));
    }

總結

從AbstractAutowireCapableBeanFactory類的requiresDestruction方法中,我們可以總結出通過以下方式之一可以爲bean提供銷燬方法。

(1)在xml配置中通過destroy-method屬性或者在java代碼中通過@PreDestroy註解指定銷燬方法

(2)在xml配置中通過destroy-method=”(inferred)”指定銷燬方法爲shutdown()方法或者close()方法。當然如果這兩個方法同時存在,那麼最終選擇的銷燬方法爲close()方法。

(3)通過實現DisposableBean接口或者實現AutoCloseable接口(JDK1.7以上)提供銷燬方法

(4)通過實現DestructionAwareBeanPostProcessor接口的bean後處理器提供銷燬邏輯

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