版权声明
- 本文原创作者:谷哥的小弟
- 作者博客地址:http://blog.csdn.net/lfdfhl

一、概述
DisposableBean 是 Spring 框架中用于定义 Bean 销毁时回调行为 的核心接口之一。它提供了一个标准化的钩子方法 destroy(),允许 Bean 在容器关闭或作用域结束前,执行资源释放、连接关闭、状态清理等销毁逻辑。
该接口与 InitializingBean 构成 Spring Bean 生命周期的对称机制 :一个负责初始化,一个负责销毁。理解 DisposableBean 的源码实现,是掌握 Spring 容器生命周期管理的关键环节。
二、接口定义
java
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)
java
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)
java
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 资源释放
java
@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 线程池关闭
java
@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 缓存清理
java
@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 核心逻辑如下:
java
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 的耦合。