Spring Framework源码解析——DisposableBean
版权声明
- 本文原创作者:谷哥的小弟
- 作者博客地址: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-methodString 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. 调用 DestructionAwareBeanPostProcessorString[] 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<>();@Overridepublic 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);@Overridepublic 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<>();@Overridepublic 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-methodif (this.destroyMethodName != null &&!(this.invokeDisposableBean && "destroy".equals(this.destroyMethodName)) &&!beanDefinition.isExternallyManagedDestroyMethod(this.destroyMethodName)) {this.destroyMethod = determineDestroyMethod();}}@Overridepublic void destroy() {// 1. 调用 DestructionAwareBeanPostProcessorif (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-methodif (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 的耦合。