概述
在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後處理器提供銷燬邏輯