当前位置: 首页 > news >正文

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);}
}

代码解析:

  1. postProcessBeforeDestruction:先通知所有 DestructionAwareBeanPostProcessor,允许在销毁前执行自定义逻辑(如解绑监听器);
  2. instanceof DisposableBean:检查 Bean 是否实现了 DisposableBean 接口;
  3. ((DisposableBean) bean).destroy():调用 destroy() 方法;
  4. 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() 的执行顺序如下:

  1. DestructionAwareBeanPostProcessor.postProcessBeforeDestruction()
  2. DisposableBean.destroy()
  3. 配置的 destroy-method(如 @Bean(destroyMethod = "close") 或 XML 中的 destroy-method

注意:如果 destroy-method 方法名恰好是 destroy,且 Bean 同时实现了 DisposableBean,则不会重复调用。


五、与 destroy-method@PreDestroy 的对比

机制类型执行顺序是否依赖 Spring API示例
DestructionAwareBeanPostProcessorSpring 扩展点最早自定义后处理器
@PreDestroyJSR-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 封装了完整的销毁逻辑,包括 @PreDestroyDisposableBeandestroy-method 的调用顺序。


八、实践与注意事项

8.1 建议使用替代方案

尽管 DisposableBean 功能完整,但官方更推荐使用 @PreDestroydestroy-method,原因如下:

  • 解耦:避免 Bean 与 Spring API 耦合;
  • 标准性@PreDestroy 是 Java 标准注解,更具通用性;
  • 灵活性destroy-method 可配置任意方法名,无需实现接口。

8.2 注意事项

  • 幂等性destroy() 方法应设计为幂等,防止重复调用导致问题;
  • 异常处理:尽量捕获内部异常,避免影响其他 Bean 的销毁;
  • 线程安全:销毁过程可能涉及共享资源,需注意并发问题;
  • 避免阻塞:长时间阻塞可能影响容器关闭速度,建议设置超时。

九、源码设计思想分析

DisposableBean 的设计体现了 Spring 的以下核心思想:

  1. 生命周期完整性:与 InitializingBean 形成“初始化-销毁”闭环;
  2. 可扩展性:通过 DestructionAwareBeanPostProcessor 支持扩展;
  3. 适配器模式:使用 DisposableBeanAdapter 统一管理多种销毁方式;
  4. 依赖顺序:逆序销毁确保依赖关系正确;
  5. 容错机制:异常被捕获并记录,不影响整体销毁流程。

DisposableBean 是 Spring 框架中实现 Bean 销毁回调的重要接口。其核心方法 destroy() 在容器关闭时自动调用,适用于资源释放、连接关闭、状态清理等场景。

尽管功能强大,但出于解耦和标准化考虑,推荐优先使用 @PreDestroy 注解。理解 DisposableBean 的执行时机、调用顺序及与 DestructionAwareBeanPostProcessor 的关系,有助于深入掌握 Spring Bean 的生命周期管理机制。

小结:

  • destroy() 在容器关闭时调用,执行顺序为:@PreDestroydestroy()destroy-method
  • DisposableBeanAdapter 封装并协调多种销毁方式;
  • 所有实现了 DisposableBean 的单例 Bean 被注册到 disposableBeans 缓存中;
  • 销毁过程逆序执行,确保依赖关系正确;
  • 推荐使用 @PreDestroy 替代,以降低与 Spring 的耦合。
http://www.lryc.cn/news/617391.html

相关文章:

  • 【PyTorch】单目标检测项目部署
  • 逃离城市与喧嚣,拥抱新的生活方式
  • 第2节 PyTorch加载数据
  • 5G与云计算对代理IP行业的深远影响
  • AI基础与实践专题:PyTorch实现线性回归
  • 开博尔雷电5数据线:120Gbps“闪电传输”,以Intel硬核基因从容优化数字生活
  • STM32CubeMX + HAL 库:用硬件IIC接口实现AT24C02 EEPROM芯片的读写操作
  • 【算法训练营Day23】贪心算法part1
  • InfluxDB 在物联网设备数据采集与分析中的应用(二)
  • Apache Ignite超时管理核心组件解析
  • 元数据管理与数据治理平台:Apache Atlas 基本搜索 Basic Search
  • 强化学习常用数据集
  • linux 秒 安装谷歌浏览器 区分ubuntu和centos 给python爬取网站使用
  • 提升行车安全的关键技术:BSD(盲点监测)与DSM(驾驶员监测)是如何工作的?
  • 剧本杀小程序系统开发:推动行业数字化转型新动力
  • 【VS Code - Qt】如何基于Docker Linux配置Windows10下的VS Code,开发调试ARM 版的Qt应用程序?
  • AI模型服务接入WAF防火墙
  • 为什么Open WebUI可以不联网问问题,而直接使用Ollama可能需要联网
  • 虚幻GAS底层原理解剖十 (网络)
  • Linux操作系统从入门到实战(二十)进程优先级
  • 汉森(1982)提出的广义矩估计法
  • ResponseBodyAdvice是什么?
  • Agent用户体验设计:人机交互的最佳实践
  • Cobalt Strike的简单搭建与使用
  • ARM基础概念 day51
  • 环境配置-拉取NVIDIA Docker镜像时出现401Unauthorized错误
  • Redis 01 数据结构
  • 第7节 大模型性能评估与优化方法指南
  • Web 开发前端与后端 API 的交互
  • 101. 孤岛的总面积