news 2026/10/2 2:09:24

深入解析 Spring Bean 销毁过程:DisposableBean、destroy-method 与 DisposableBeanAdapter 源码全解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入解析 Spring Bean 销毁过程:DisposableBean、destroy-method 与 DisposableBeanAdapter 源码全解
  • 示例工程
  • 文档

【免费下载链接】spring-reading

涵盖了 Spring 框架的核心概念和关键功能,包括控制反转(IOC)容器的使用,面向切面编程(AOP)的原理与实践,事务管理的方式与实现,Spring MVC 的流程与控制器工作机制,以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外,它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程,以及对 Spring 源码的编程风格与设计模式的深入探讨。

项目地址:https://gitcode.com/GitHub_Trending/sp/spring-reading
点击查看免费下载

Spring 容器的职责远不止创建与装配 Bean——在容器关闭、Bean 生命周期结束时,它还要负责有条不紊地完成资源释放与清理。本文以 spring-reading 仓库中 spring-core-destroyBean 模块为骨架,完整还原 Bean 销毁阶段的核心机制:DisposableBean接口、destroy-method配置、@PreDestroy注解以及DestructionAwareBeanPostProcessor后置处理器如何被串联执行,并从AbstractApplicationContext#close到DisposableBeanAdapter#destroy逐层剖析源码调用链。读完本文,你将掌握 Spring Bean 销毁的全部入口、执行顺序与底层实现,并能在真实项目中正确设计资源清理逻辑。

一、知识储备:理解 Bean 销毁的前提

Bean 的销毁是 Bean 完整生命周期(定义注册 → 实例化 → 属性注入 → 初始化 → 销毁)的最后一环,理解它之前需要先掌握三个前置过程:

  1. Bean 的定义注册过程:加载并解析配置文件,从中提取类名、作用域(singleton / prototype)、属性值等 Bean 元数据,通过唯一标识符注册到容器,供后续获取与管理。可参考 spring-core-registerBeanDefinition。
  2. Bean 的初始化过程:通过构造函数实例化 Bean,随后进行属性注入满足依赖关系;若 Bean 实现了 Aware 接口,容器通过回调注入上下文信息;注册的后置处理器在初始化前后对 Bean 做额外处理;InitializingBean#afterPropertiesSet或配置中的init-method用于执行自定义初始化逻辑。可参考 spring-core-getBean。
  3. Bean 的依赖解析过程:容器在 ApplicationContext 中查找依赖定义并完成注入,通过提前暴露的代理对象解决循环引用,并支持延迟依赖解析以提升启动性能。可参考 spring-core-resolveDependency。

二、基本描述与主要功能

容器销毁 Bean 时,会按照以下机制依次执行清理逻辑:

  1. 执行自定义销毁逻辑:调用实现了DisposableBean接口的 Bean 的destroy方法,用于释放资源或执行必要的清理工作。
  2. 调用自定义销毁方法:如果 Bean 配置中通过destroy-method属性指定了自定义销毁方法,容器同样会调用它。
  3. 后置处理器清理工作:对于实现了DestructionAwareBeanPostProcessor接口的后置处理器,容器在销毁前调用其postProcessBeforeDestruction方法(该接口同时提供postProcessAfterDestruction语义的扩展空间),允许进行额外的清理。
  4. 执行@PreDestroy注解方法:通过@PreDestroy注解标记 Bean 方法,确保销毁时执行特定的业务清理逻辑。
  5. 触发销毁通知:Spring 容器会触发销毁通知,通知相关监听器或观察者,允许应用程序在 Bean 销毁时执行特定处理。

三、最佳实践:一个可运行的销毁示例

本模块的核心示例位于 DestroyBeanApplication.java,采用基于注解的配置方式:创建应用上下文、注册 Bean、刷新容器,最后关闭容器触发销毁阶段。

public class DestroyBeanApplication { public static void main(String[] args) { // 创建一个基于注解的应用程序上下文对象 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); // 注册配置类 MyBean,告诉 Spring 在容器中管理这个配置类所定义的 bean context.register(MyBean.class); // 刷新应用程序上下文,初始化并启动 Spring 容器 context.refresh(); // 关闭应用程序上下文,销毁 Spring 容器并释放资源 context.close(); } }

对应的 MyBean.java 实现了DisposableBean接口,在destroy方法中输出一条消息:

public class MyBean implements DisposableBean { @Override public void destroy() throws Exception { System.out.println("MyBean被销毁了"); } }

运行后控制台输出:

MyBean被销毁了

这说明:当 Spring 容器关闭时,会触发 Bean 的销毁阶段,实现了DisposableBean接口的 Bean 会调用其destroy方法。该示例模块的构建配置位于 pom.xml,其父模块 spring-core 将getBean、resolveDependency、registerBeanDefinition与destroyBean四个子模块聚合在一起,恰好覆盖 Bean 生命周期的完整链路。

3.1 五种常见的销毁写法对照

除DisposableBean接口外,Spring 还支持多种等价的销毁配置方式,它们都会被DisposableBeanAdapter统一收纳执行:

方式写法执行时机
接口回调implements DisposableBean,重写destroy()容器关闭时
注解方法上标注@PreDestroy(JSR-250)容器关闭时
XML 配置<bean destroy-method="close">容器关闭时
Java 配置@Bean(destroyMethod = "close")容器关闭时
后置处理器实现DestructionAwareBeanPostProcessor#postProcessBeforeDestruction容器关闭时(先于上述回调执行)

其中DestructionAwareBeanPostProcessor的完整用法可参考 spring-interface-destructionAwareBeanPostProcessor 模块:其典型场景是在 Bean 销毁前关闭连接、释放文件句柄等资源,并可通过重写requiresDestruction(Object bean)方法(默认返回true,自 Spring 4.3 起引入)精确控制哪些 Bean 需要执行销毁回调,避免无谓的性能开销。

四、时序图:销毁全流程一览

Bean 销毁过程分为「注册适配器」与「Bean 销毁」两个阶段,整体时序如下:

sequenceDiagram Title: Bean的销毁过程时序图 par 注册适配器阶段 DestroyBeanApplication->>AbstractApplicationContext: refresh() Note over AbstractApplicationContext: 初始化应用程序上下文 AbstractApplicationContext->>AbstractApplicationContext: finishBeanFactoryInitialization(beanFactory) Note over AbstractApplicationContext: 完成bean工厂的初始化 AbstractApplicationContext->>DefaultListableBeanFactory: preInstantiateSingletons() Note over DefaultListableBeanFactory: 预实例化所有单例bean DefaultListableBeanFactory->>AbstractBeanFactory: getBean(name) Note over AbstractBeanFactory: 从bean工厂获取bean实例 AbstractBeanFactory->>AbstractBeanFactory: doGetBean(name, requiredType, args, typeCheckOnly) Note over AbstractBeanFactory: 实际获取bean的方法 AbstractBeanFactory->>DefaultSingletonBeanRegistry: getSingleton(beanName, singletonFactory) Note over DefaultSingletonBeanRegistry: 从单例注册表获取单例bean DefaultSingletonBeanRegistry->>AbstractBeanFactory: getObject() Note over AbstractBeanFactory: 获取bean的实例对象 AbstractBeanFactory->>AbstractAutowireCapableBeanFactory: createBean(beanName, mbd, args) Note over AbstractAutowireCapableBeanFactory: 创建bean实例 AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory: doCreateBean(beanName, mbdToUse, args) Note over AbstractAutowireCapableBeanFactory: 实际创建bean实例的方法 AbstractAutowireCapableBeanFactory->>AbstractBeanFactory: registerDisposableBeanIfNecessary(beanName, bean, mbd) Note over AbstractBeanFactory: 注册bean的销毁适配器 AbstractBeanFactory->>DisposableBeanAdapter: new DisposableBeanAdapter(bean, beanName, beanDefinition, postProcessors, acc) Note over DisposableBeanAdapter: 创建bean的销毁适配器 DisposableBeanAdapter->>AbstractBeanFactory: 返回销毁Bean适配器 Note over AbstractBeanFactory: 返回销毁Bean适配器 AbstractBeanFactory->>DefaultSingletonBeanRegistry: registerDisposableBean(beanName, bean) Note over DefaultSingletonBeanRegistry: 注册单例bean的销毁适配器 end par Bean销毁阶段 DestroyBeanApplication->>AbstractApplicationContext: close() Note over AbstractApplicationContext: 关闭应用程序上下文 AbstractApplicationContext->>AbstractApplicationContext: doClose() Note over AbstractApplicationContext: 执行关闭操作 AbstractApplicationContext->>AbstractApplicationContext: destroyBeans() Note over AbstractApplicationContext: 销毁所有bean AbstractApplicationContext->>DefaultListableBeanFactory: destroySingletons() Note over DefaultListableBeanFactory: 销毁所有单例bean DefaultListableBeanFactory->>DefaultSingletonBeanRegistry: destroySingletons() Note over DefaultSingletonBeanRegistry: 销毁所有单例bean DefaultSingletonBeanRegistry->>DefaultSingletonBeanRegistry: destroySingleton(beanName) Note over DefaultSingletonBeanRegistry: 销毁单例bean DefaultSingletonBeanRegistry->>DefaultSingletonBeanRegistry: destroyBean(beanName, disposableBean) Note over DefaultSingletonBeanRegistry: 销毁bean的销毁适配器 DefaultSingletonBeanRegistry->>DisposableBeanAdapter: destroy() Note over DisposableBeanAdapter: 调用bean的destroy方法 DisposableBeanAdapter->>MyBean: destroy() Note over MyBean: MyBean的销毁逻辑执行 end

五、源码分析(上):销毁适配器的注册

销毁逻辑并非在 Bean 创建时立即执行,而是先注册一个「销毁适配器」,待容器关闭时统一触发。整个注册链路由refresh启动。

5.1 refresh 与预实例化单例

在org.springframework.context.support.AbstractApplicationContext#refresh方法中,重点关注finishBeanFactoryInitialization(beanFactory),它会实例化所有剩余非懒加载的单例 Bean:

@Override public void refresh() throws BeansException, IllegalStateException { // ... [代码部分省略以简化] // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // ... [代码部分省略以简化] }

finishBeanFactoryInitialization继续调用DefaultListableBeanFactory#preInstantiateSingletons:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // ... [代码部分省略以简化] // 完成所有剩余非懒加载的单列Bean对象。 beanFactory.preInstantiateSingletons(); }

preInstantiateSingletons的核心目的是预先实例化所有非懒加载的单例 Bean,对容器中定义的每一个单例 Bean 调用getBean,触发实例化、初始化与依赖注入:

public void preInstantiateSingletons() throws BeansException { // ... [代码部分省略以简化] // 循环遍历所有bean的名称 for (String beanName : beanNames) { getBean(beanName); } // ... [代码部分省略以简化] }

5.2 getBean 与 doGetBean

AbstractBeanFactory#getBean委托doGetBean完成实际获取:

@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }

doGetBean检查 Bean 是否已是单例并已创建;若尚未创建,则通过getSingleton(beanName, singletonFactory)创建新实例(该过程会处理循环引用等异常情况,并确保返回类型正确),这是 Spring 容器 Bean 生命周期管理的核心部分:

protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { // ... [代码部分省略以简化] // 开始创建bean实例 if (mbd.isSingleton()) { // 如果bean是单例的,我们会尝试从单例缓存中获取 // 如果不存在,则使用lambda创建一个新的实例 sharedInstance = getSingleton(beanName, () -> { try { // 尝试创建bean实例 return createBean(beanName, mbd, args); } catch (BeansException ex) { // ... [代码部分省略以简化] } }); // 对于某些bean(例如FactoryBeans),可能需要进一步处理以获取真正的bean实例 beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // ... [代码部分省略以简化] // 确保返回的bean实例与请求的类型匹配 return adaptBeanInstance(name, beanInstance, requiredType); }

5.3 从单例缓存获取或创建

DefaultSingletonBeanRegistry#getSingleton(beanName, singletonFactory)负责从单例缓存中获取已存在的实例,或使用ObjectFactory创建新实例——这是保证 Bean 单例性的关键:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { // 断言bean名称不能为空 Assert.notNull(beanName, "Bean name must not be null"); // 同步访问单例对象缓存,确保线程安全 synchronized (this.singletonObjects) { // 从缓存中获取单例对象 Object singletonObject = this.singletonObjects.get(beanName); // 如果缓存中没有找到 if (singletonObject == null) { // ... [代码部分省略以简化] try { // 使用工厂创建新的单例实例 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // ... [代码部分省略以简化] } catch (BeanCreationException ex) { // ... [代码部分省略以简化] } finally { // ... [代码部分省略以简化] } // ... [代码部分省略以简化] } // 返回单例对象 return singletonObject; } }

5.4 createBean 与 doCreateBean:销毁适配器在此埋点

AbstractAutowireCapableBeanFactory#createBean的核心是调用doCreateBean,后者真正执行 Bean 实例化、属性填充与初始化,并在收尾处注册销毁适配器:

@Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // ... [代码部分省略以简化] try { // 正常的bean实例化、属性注入和初始化。 // 这里是真正进行bean创建的部分。 Object beanInstance = doCreateBean(beanName, mbdToUse, args); // 记录bean成功创建的日志 if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // ... [代码部分省略以简化] } catch (Throwable ex) { // ... [代码部分省略以简化] } }

doCreateBean的关键点在于:创建 Bean 实例的过程中注册了销毁适配器,以便容器关闭时执行相应销毁逻辑:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // 在此注册bean以便在销毁时进行处理。 try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { // ... [代码部分省略以简化] } }

5.5 registerDisposableBeanIfNecessary:按作用域注册销毁逻辑

AbstractBeanFactory#registerDisposableBeanIfNecessary首先检查 Bean 是否为单例且需要销毁逻辑。若为单例,注册一个DisposableBeanAdapter(负责执行DestructionAwareBeanPostProcessors、DisposableBean接口及自定义销毁方法);对于自定义作用域,则查找对应Scope并注册销毁回调:

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) { // ... [代码部分省略以简化] // 检查是否为原型作用域(prototype),以及是否需要销毁 if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) { if (mbd.isSingleton()) { // 如果是单例作用域,注册一个 DisposableBean 适配器,该适配器执行所有销毁工作 // 包括 DestructionAwareBeanPostProcessors、DisposableBean 接口、自定义销毁方法等 registerDisposableBean(beanName, new DisposableBeanAdapter( bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc)); } else { // 如果是自定义作用域,找到相应的 Scope 并注册销毁回调 Scope scope = this.scopes.get(mbd.getScope()); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'"); } // 注册一个 DisposableBean 适配器,该适配器执行所有销毁工作 scope.registerDestructionCallback(beanName, new DisposableBeanAdapter( bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc)); } } }

这里有两个值得注意的细节:

  • !mbd.isPrototype()判断:原型作用域的 Bean 默认不参与容器销毁管理,需要使用者自行释放其持有的资源(详见第八节注意事项)。
  • requiresDestruction预筛选:若 Bean 既没有销毁方法、也没有相关的DestructionAwareBeanPostProcessor,则根本不会注册适配器,避免无谓开销。

5.6 requiresDestruction 与 DisposableBeanAdapter 构造

requiresDestruction判断 Bean 是否需要销毁:类型非NullBean且存在销毁方法或相关的DestructionAwareBeanPostProcessor时返回true:

protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) { return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors( bean, getBeanPostProcessorCache().destructionAware)))); }

DisposableBeanAdapter的构造方法负责识别销毁方式:检查是否实现DisposableBean接口、推断自定义销毁方法名(inferDestroyMethodIfNecessary)、过滤匹配的DestructionAwareBeanPostProcessor列表,为容器关闭时的执行做好全部准备:

public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition, List<DestructionAwareBeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) { // 确保待销毁的 Bean 实例不为 null Assert.notNull(bean, "Disposable bean must not be null"); // 初始化实例变量 this.bean = bean; this.beanName = beanName; // 确定是否需要调用 DisposableBean 接口的 destroy 方法 this.invokeDisposableBean = (this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy")); // 是否允许访问非公共方法 this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed(); this.acc = acc; // 推断销毁方法的名称 String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition); // 如果存在销毁方法,并且不是外部管理的 destroy 方法,则进行相关处理 if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) && !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { // 记录销毁方法的名称 this.destroyMethodName = destroyMethodName; // 确定销毁方法 Method destroyMethod = determineDestroyMethod(destroyMethodName); // 如果找不到销毁方法,并且 Bean 定义要求强制存在,则抛出异常 if (destroyMethod == null) { // ... [代码部分省略以简化] } // 否则,检查销毁方法的合法性 else { if (destroyMethod.getParameterCount() > 0) { Class<?>[] paramTypes = destroyMethod.getParameterTypes(); // ... [代码部分省略以简化] } // 获取销毁方法的接口方法(如果存在) destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod); } // 记录销毁方法 this.destroyMethod = destroyMethod; } // 过滤与销毁相关的 BeanPostProcessor this.beanPostProcessors = filterPostProcessors(postProcessors, bean); }

最后,适配器通过DefaultSingletonBeanRegistry#registerDisposableBean存入disposableBeans集合(同步块保证线程安全),完成注册阶段:

public void registerDisposableBean(String beanName, DisposableBean bean) { // 使用同步块确保线程安全 synchronized (this.disposableBeans) { // 将待销毁的 Bean 放入 disposableBeans 集合中 this.disposableBeans.put(beanName, bean); } }

六、源码分析(下):Bean 的实际销毁

6.1 close → doClose → destroyBeans

AbstractApplicationContext#close在startupShutdownMonitor对象上启动同步块,确保同一时刻只有一个线程执行关闭逻辑(防止多线程资源竞争或数据不一致),随后调用doClose:

@Override public void close() { synchronized (this.startupShutdownMonitor) { doClose(); // ... [代码部分省略以简化] } }

doClose中调用destroyBeans:

protected void doClose() { // ... [代码部分省略以简化] // Destroy all cached singletons in the context's BeanFactory. destroyBeans(); // ... [代码部分省略以简化] }

destroyBeans通过getBeanFactory()取得BeanFactory并调用destroySingletons,销毁所有缓存的单例 Bean:

protected void destroyBeans() { getBeanFactory().destroySingletons(); }

6.2 destroySingletons:倒序销毁保证依赖顺序

DefaultListableBeanFactory#destroySingletons先调用父类DefaultSingletonBeanRegistry#destroySingletons,确保继承的销毁逻辑得到执行:

@Override public void destroySingletons() { super.destroySingletons(); // ... [代码部分省略以简化] }

父类方法取出disposableBeans的全部 key(即注册了销毁适配器的 Bean 名称),倒序循环逐个销毁——后创建的先销毁,从而正确处理依赖关系(先创建的 Bean 应该后被销毁):

public void destroySingletons() { // ... [代码部分省略以简化] String[] disposableBeanNames; synchronized (this.disposableBeans) { disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet()); } for (int i = disposableBeanNames.length - 1; i >= 0; i--) { destroySingleton(disposableBeanNames[i]); } // ... [代码部分省略以简化] }

6.3 destroySingleton:移除并执行销毁

DefaultListableBeanFactory#destroySingleton同样先调用父类实现:

@Override public void destroySingleton(String beanName) { super.destroySingleton(beanName); // ... [代码部分省略以简化] }

父类DefaultSingletonBeanRegistry#destroySingleton从缓存中移除该单例、从disposableBeans取出对应的DisposableBean适配器,然后调用destroyBean执行实际销毁:

public void destroySingleton(String beanName) { // 从已注册的单例中移除指定名称的单例 Bean removeSingleton(beanName); // 获取对应的 DisposableBean 实例 DisposableBean disposableBean; synchronized (this.disposableBeans) { disposableBean = (DisposableBean) this.disposableBeans.remove(beanName); } // 执行销毁逻辑 destroyBean(beanName, disposableBean); }

6.4 destroyBean:级联销毁与依赖清理

destroyBean负责销毁指定 Bean,包含四个关键步骤:触发销毁依赖于该 Bean 的其他 Bean(dependentBeanMap)、执行 Bean 自身的destroy方法、销毁该 Bean 包含的其他 Bean(containedBeanMap)、从其他 Bean 的依赖关系中移除已销毁 Bean 并清理依赖缓存(dependenciesForBeanMap):

protected void destroyBean(String beanName, @Nullable DisposableBean bean) { // 触发销毁依赖于该 Bean 的其他 Bean... Set<String> dependencies; // 在完全同步的情况下,以确保获取的 Set 是线程安全的 synchronized (this.dependentBeanMap) { dependencies = this.dependentBeanMap.remove(beanName); } if (dependencies != null) { // ... [代码部分省略以简化] for (String dependentBeanName : dependencies) { destroySingleton(dependentBeanName); } } // 实际执行 Bean 的销毁逻辑... if (bean != null) { try { bean.destroy(); } catch (Throwable ex) { // ... [代码部分省略以简化] } } // 触发销毁该 Bean 包含的其他 Bean... Set<String> containedBeans; synchronized (this.containedBeanMap) { // 在完全同步的情况下,以确保获取的 Set 是断开连接的 containedBeans = this.containedBeanMap.remove(beanName); } if (containedBeans != null) { for (String containedBeanName : containedBeans) { destroySingleton(containedBeanName); } } // 从其他 Bean 的依赖关系中移除已销毁的 Bean... synchronized (this.dependentBeanMap) { for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) { Map.Entry<String, Set<String>> entry = it.next(); Set<String> dependenciesToClean = entry.getValue(); dependenciesToClean.remove(beanName); if (dependenciesToClean.isEmpty()) { it.remove(); } } } // 移除已销毁 Bean 的准备好的依赖信息 this.dependenciesForBeanMap.remove(beanName); }

6.5 DisposableBeanAdapter#destroy:销毁逻辑的总调度

DisposableBeanAdapter#destroy实现DisposableBean接口的销毁方法,是整个销毁流程的调度核心,严格按以下顺序执行:

  1. 前置销毁处理:遍历所有匹配的DestructionAwareBeanPostProcessor,调用postProcessBeforeDestruction(bean, beanName);
  2. 调用DisposableBean接口的destroy方法(若实现了该接口);
  3. 执行自定义销毁方法:优先调用构造时确定的destroyMethod;否则按destroyMethodName重新确定方法后调用(通常对应@PreDestroy或destroy-method配置)。
@Override public void destroy() { // 执行 DestructionAwareBeanPostProcessor 的前置销毁处理 if (!CollectionUtils.isEmpty(this.beanPostProcessors)) { for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) { processor.postProcessBeforeDestruction(this.bean, this.beanName); } } // 如果实现了 DisposableBean 接口,则调用其 destroy 方法 if (this.invokeDisposableBean) { // ... [代码部分省略以简化] try { // ... [代码部分省略以简化] ((DisposableBean) this.bean).destroy(); } catch (Throwable ex) { // ... [代码部分省略以简化] } } // 如果存在自定义的销毁方法,则执行 if (this.destroyMethod != null) { invokeCustomDestroyMethod(this.destroyMethod); } // 如果存在指定名称的自定义销毁方法,则查找并执行 else if (this.destroyMethodName != null) { Method methodToInvoke = determineDestroyMethod(this.destroyMethodName); if (methodToInvoke != null) { // 获取接口方法(如果存在)并执行自定义销毁方法 invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke)); } } }

6.6 销毁执行的完整顺序小结

综上,单个 Bean 在销毁阶段的执行顺序可概括为:

  1. DestructionAwareBeanPostProcessor#postProcessBeforeDestruction(多个处理器按注册顺序执行);
  2. @PreDestroy注解方法(由CommonAnnotationBeanPostProcessor等后置处理器在步骤 1 中触发);
  3. DisposableBean#destroy接口方法;
  4. 配置的destroy-method(如@Bean(destroyMethod)、XMLdestroy-method或@Bean默认推断的close/shutdown)。

七、注意事项

  1. 销毁方法避免抛出异常:销毁方法中的异常会影响其他 Bean 的销毁过程,应尽量避免抛出;如有异常,最好记录日志后继续。
  2. 注意 Bean 的依赖关系:确保销毁顺序符合依赖关系——先销毁依赖较少的 Bean,再销毁依赖较多的 Bean。Spring 通过disposableBeans倒序遍历与dependentBeanMap级联销毁尽量保证顺序正确。
  3. 注意 Bean 的生命周期和作用域:单例 Bean 的销毁在容器关闭时触发;原型(Prototype)Bean 创建后由调用方持有,Spring 容器不负责其销毁,需要手动管理(例如在业务代码中显式调用清理方法,或借助@Scope自定义作用域的registerDestructionCallback)。

八、总结

8.1 最佳实践总结

  1. 创建应用程序上下文:使用AnnotationConfigApplicationContext创建基于注解的上下文对象;
  2. 注册 Bean:调用context.register(MyBean.class)将 Bean 类注册进容器;
  3. 刷新上下文:调用context.refresh()初始化并启动 Spring 容器;
  4. 容器关闭:调用context.close()关闭上下文,触发 Bean 销毁阶段;
  5. Bean 销毁:MyBean实现DisposableBean接口,容器关闭时调用其destroy方法,控制台输出MyBean被销毁了,证明销毁流程已执行。

8.2 源码分析总结

  1. 注册 Bean 销毁适配器:AbstractApplicationContext#finishBeanFactoryInitialization→DefaultListableBeanFactory#preInstantiateSingletons预实例化所有非懒加载单例 Bean,实例化过程中通过registerDisposableBeanIfNecessary为需要销毁的 Bean 注册DisposableBeanAdapter(区分单例与自定义作用域),确保容器关闭时能够执行相应销毁逻辑。
  2. Bean 销毁:
    • 容器关闭时,AbstractApplicationContext#close触发销毁流程,destroyBeans调用DefaultListableBeanFactory#destroySingletons销毁所有缓存的单例 Bean;
    • destroySingletons遍历disposableBeans集合,倒序销毁所有待销毁 Bean,以保证依赖关系正确;
    • destroyBean级联销毁依赖 Bean 与被包含 Bean,执行 Bean 的destroy方法,并清理依赖关系与依赖缓存;
    • 最终由DisposableBeanAdapter#destroy统一调度:先执行DestructionAwareBeanPostProcessor#postProcessBeforeDestruction前置销毁处理,再调用DisposableBean#destroy,最后执行自定义销毁方法(含@PreDestroy与destroy-method配置),完整覆盖 Bean 销毁阶段的所有清理入口。

结合 spring-core-getBean 模块可以看到:doCreateBean在 Bean 创建之初就为销毁埋下了「注册适配器」的钩子,而close()则在容器关闭时将其兑现——创建与销毁首尾呼应,共同构成 Spring Bean 生命周期管理的闭环。理解这一过程,是设计可靠资源清理逻辑(连接池关闭、线程池 shutdown、临时文件删除等)的基础。

  • 示例工程
  • 文档

【免费下载链接】spring-reading

涵盖了 Spring 框架的核心概念和关键功能,包括控制反转(IOC)容器的使用,面向切面编程(AOP)的原理与实践,事务管理的方式与实现,Spring MVC 的流程与控制器工作机制,以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外,它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程,以及对 Spring 源码的编程风格与设计模式的深入探讨。

项目地址:https://gitcode.com/GitHub_Trending/sp/spring-reading
点击查看免费下载
上一篇:终极指南:10分钟搞定Kodi中文插件库,解锁海量中文影视资源
下一篇:浏览器端AI标注解决方案:Make Sense如何重构计算机视觉数据工作流

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 2:04:51

h3.c开发者指南:用公开C API构建你自己的本地文生视频应用

h3.c开发者指南&#xff1a;用公开C API构建你自己的本地文生视频应用 【免费下载链接】h3.c MiniMax H3 inference engine for Mac computers 项目地址: https://gitcode.com/gh_mirrors/h3/h3.c h3.c&#xff08;又名 h3-metal&#xff09;是一个运行在 Apple Silicon…

作者头像 李华
网站建设 2026/10/2 2:01:37

AI Agent支付背后的七套协议:从TLS到MCP全解析

AI Agent支付&#xff0c;从2024年底开始就成了支付圈最热的关键词。但真正立案子去接支付协议时我才发现&#xff1a;所谓AI支付&#xff0c;根本没有一套现成的"AI支付协议"&#xff0c;它是在过去四十年的支付技术地基上&#xff0c;一层一层堆出来的。翻了一遍家…

作者头像 李华
网站建设 2026/10/2 2:00:20

HowToCook 菜谱实战:韭菜炒蛋的做法与大火快炒技术要点解析

文档教程 【免费下载链接】HowToCook Programmers guide about how to cook at home. 项目地址&#xff1a; https://gitcode.com/GitHub_Trending/ho/HowToCook 点击查看 免费下载 韭菜炒蛋是一道经典家常快炒菜&#xff0c;本文以开源项目 HowToCook 仓库中的 韭菜炒蛋.md 菜…

作者头像 李华