版权声明
- 本文原创作者:谷哥的小弟
- 作者博客地址:http://blog.csdn.net/lfdfhl
一、概述
DisposableBean
是 Spring 框架中用于定义 Bean 销毁时回调行为的核心接口之一。它提供了一个标准化的钩子方法 destroy()
,允许 Bean 在容器关闭或作用域结束前,执行资源释放、连接关闭、状态清理等销毁逻辑。
该接口与 InitializingBean
构成 Spring Bean 生命周期的对称机制:一个负责初始化,一个负责销毁。理解 DisposableBean
的源码实现,是掌握 Spring 容器生命周期管理的关键环节。
二、接口定义
public interface DisposableBean {
/**
* 在 Bean 被销毁前由容器调用
* 用于释放资源、关闭连接、清理缓存等操作
* @throws Exception 如果销毁过程出错
*/
void destroy() throws Exception;
}
destroy()
:当 Bean 生命周期结束时(如容器关闭、作用域结束),Spring 容器会自动调用此方法。- 执行时机:在
DestructionAwareBeanPostProcessor.postProcessBeforeDestruction()
之后,destroy-method
之前。 - 异常处理:若销毁失败,应抛出
Exception
,Spring 会记录日志但通常不会中断容器关闭流程(除非配置严格模式)。
三、核心执行流程分析
DisposableBean
的调用发生在容器关闭阶段,其核心逻辑由 AbstractBeanFactory.destroyBean()
和 DefaultSingletonBeanRegistry.destroySingletons()
协同完成。
3.1 destroyBean()
方法源码(位于 AbstractBeanFactory
)
public void destroyBean(Object bean) {
destroyBean(getBeanNameForBeanInstance(bean), bean);
}
public void destroyBean(String beanName, Object bean) {
DestructionAwareBeanPostProcessor.postProcessBeforeDestruction(bean, beanName);
if (bean instanceof DisposableBean) {
try {
((DisposableBean) bean).destroy();
}
catch (Throwable ex) {
throw new BeanCreationException(
"Destruction of bean with name '" + beanName + "' failed", ex);
}
}
// 调用配置的 destroy-method
String destroyMethodName = getDestroyMethodName(beanName);
if (destroyMethodName != null &&
!(bean instanceof DisposableBean && "destroy".equals(destroyMethodName))) {
invokeCustomDestroyMethod(bean, destroyMethodName);
}
}
代码解析:
postProcessBeforeDestruction
:先通知所有DestructionAwareBeanPostProcessor
,允许在销毁前执行自定义逻辑(如解绑监听器);instanceof DisposableBean
:检查 Bean 是否实现了DisposableBean
接口;((DisposableBean) bean).destroy()
:调用destroy()
方法;invokeCustomDestroyMethod
:最后调用配置的destroy-method
(如 XML 中的destroy-method="close"
)。
3.2 destroySingletons()
方法源码(位于 DefaultSingletonBeanRegistry
)
public void destroySingletons() {
if (logger.isTraceEnabled()) {
logger.trace("Destroying singletons in " + this);
}
synchronized (this.singletonObjects) {
this.singletonsCurrentlyInDestruction = true;
}
// 1. 调用 DestructionAwareBeanPostProcessor
String[] disposableBeanNames;
synchronized (this.disposableBeans) {
disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
}
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
destroySingleton(disposableBeanNames[i]);
}
// 2. 清理所有缓存
this.containedBeanMap.clear();
this.dependentBeanMap.clear();
this.dependenciesForBeanMap.clear();
clearSingletonCache();
}
代码解析:
this.disposableBeans
:这是一个Map<String, Object>
,在 Bean 创建时注册,记录所有实现了DisposableBean
或配置了destroy-method
的单例 Bean;- 逆序销毁:从后往前遍历
disposableBeanNames
,确保依赖关系正确的销毁顺序(被依赖的后销毁); destroySingleton(String)
:触发单个 Bean 的销毁流程。
四、执行顺序详解
DisposableBean.destroy()
的执行顺序如下:
DestructionAwareBeanPostProcessor.postProcessBeforeDestruction()
DisposableBean.destroy()
- 配置的
destroy-method
(如@Bean(destroyMethod = "close")
或 XML 中的destroy-method
)
注意:如果
destroy-method
方法名恰好是destroy
,且 Bean 同时实现了DisposableBean
,则不会重复调用。
五、与 destroy-method
和 @PreDestroy
的对比
机制 | 类型 | 执行顺序 | 是否依赖 Spring API | 示例 |
---|---|---|---|---|
DestructionAwareBeanPostProcessor |
Spring 扩展点 | 最早 | 是 | 自定义后处理器 |
@PreDestroy |
JSR-250 注解 | 第二(由 CommonAnnotationBeanPostProcessor 触发) |
否(标准 Java EE 注解) | @PreDestroy public void cleanup() |
DisposableBean.destroy() |
Spring 接口 | 第三 | 是 | public void destroy() |
destroy-method |
配置方法 | 最后 | 否 | <bean destroy-method="close"/> |
特别说明:
@PreDestroy
实际上是通过CommonAnnotationBeanPostProcessor
实现的,它实现了DestructionAwareBeanPostProcessor
接口,因此其执行早于DisposableBean.destroy()
。
六、应用场景
6.1 资源释放
@Component
public class DatabaseConnectionPool implements DisposableBean {
private List<Connection> connections = new ArrayList<>();
@Override
public void destroy() throws Exception {
for (Connection conn : connections) {
if (conn != null && !conn.isClosed()) {
conn.close();
}
}
connections.clear();
}
}
6.2 线程池关闭
@Component
public class TaskExecutor implements DisposableBean {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
@Override
public void destroy() throws Exception {
executor.shutdown();
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
}
}
6.3 缓存清理
@Component
public class LocalCacheService implements DisposableBean {
private final Map<String, Object> cache = new ConcurrentHashMap<>();
@Override
public void destroy() throws Exception {
cache.clear();
logger.info("Local cache cleared on shutdown");
}
}
七、注册机制:DisposableBeanAdapter
Spring 并不直接持有 DisposableBean
实例,而是通过 DisposableBeanAdapter
进行适配和封装。
DisposableBeanAdapter
核心逻辑如下:
class DisposableBeanAdapter implements DisposableBean, Runnable {
private final Object bean;
private final String beanName;
private String destroyMethodName;
private boolean invokeDisposableBean;
private boolean nonPublicAccessAllowed;
public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
List<DestructionAwareBeanPostProcessor> postProcessors, AccessControlContext acc) {
this.bean = bean;
this.beanName = beanName;
this.invokeDisposableBean = (this.bean instanceof DisposableBean);
this.destroyMethodName = (beanDefinition != null ? beanDefinition.getDestroyMethodName() : null);
// 如果方法名不是 "destroy" 或者 Bean 没有实现 DisposableBean,则需要调用 destroy-method
if (this.destroyMethodName != null &&
!(this.invokeDisposableBean && "destroy".equals(this.destroyMethodName)) &&
!beanDefinition.isExternallyManagedDestroyMethod(this.destroyMethodName)) {
this.destroyMethod = determineDestroyMethod();
}
}
@Override
public void destroy() {
// 1. 调用 DestructionAwareBeanPostProcessor
if (this.postProcessors != null) {
for (DestructionAwareBeanPostProcessor processor : this.postProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
// 2. 调用 DisposableBean.destroy()
if (this.invokeDisposableBean) {
try {
((DisposableBean) this.bean).destroy();
}
catch (Throwable ex) {
throw new BeanCreationException(
"Destruction of bean with name '" + this.beanName + "' failed", ex);
}
}
// 3. 调用 destroy-method
if (this.destroyMethod != null) {
try {
invokeCustomDestroyMethod(this.destroyMethod);
}
catch (Throwable ex) {
throw new BeanCreationException(
"Destruction of bean with name '" + this.beanName + "' failed", ex);
}
}
}
}
注意事项:
DisposableBeanAdapter
封装了完整的销毁逻辑,包括@PreDestroy
、DisposableBean
、destroy-method
的调用顺序。
八、实践与注意事项
8.1 建议使用替代方案
尽管 DisposableBean
功能完整,但官方更推荐使用 @PreDestroy
或 destroy-method
,原因如下:
- 解耦:避免 Bean 与 Spring API 耦合;
- 标准性:
@PreDestroy
是 Java 标准注解,更具通用性; - 灵活性:
destroy-method
可配置任意方法名,无需实现接口。
8.2 注意事项
- 幂等性:
destroy()
方法应设计为幂等,防止重复调用导致问题; - 异常处理:尽量捕获内部异常,避免影响其他 Bean 的销毁;
- 线程安全:销毁过程可能涉及共享资源,需注意并发问题;
- 避免阻塞:长时间阻塞可能影响容器关闭速度,建议设置超时。
九、源码设计思想分析
DisposableBean
的设计体现了 Spring 的以下核心思想:
- 生命周期完整性:与
InitializingBean
形成“初始化-销毁”闭环; - 可扩展性:通过
DestructionAwareBeanPostProcessor
支持扩展; - 适配器模式:使用
DisposableBeanAdapter
统一管理多种销毁方式; - 依赖顺序:逆序销毁确保依赖关系正确;
- 容错机制:异常被捕获并记录,不影响整体销毁流程。
DisposableBean
是 Spring 框架中实现 Bean 销毁回调的重要接口。其核心方法 destroy()
在容器关闭时自动调用,适用于资源释放、连接关闭、状态清理等场景。
尽管功能强大,但出于解耦和标准化考虑,推荐优先使用 @PreDestroy
注解。理解 DisposableBean
的执行时机、调用顺序及与 DestructionAwareBeanPostProcessor
的关系,有助于深入掌握 Spring Bean 的生命周期管理机制。
小结:
destroy()
在容器关闭时调用,执行顺序为:@PreDestroy
→destroy()
→destroy-method
;- 由
DisposableBeanAdapter
封装并协调多种销毁方式; - 所有实现了
DisposableBean
的单例 Bean 被注册到disposableBeans
缓存中; - 销毁过程逆序执行,确保依赖关系正确;
- 推荐使用
@PreDestroy
替代,以降低与 Spring 的耦合。