java spring 09 Bean的销毁过程 上 在docreatebean中登记要销毁的bean
1.Bean销毁是发送在Spring容器关闭过程中的
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) context.getBean("userService");userService.test();// 容器关闭context.close();
2.在Bean创建过程中,在最后(初始化之后),有一个步骤会去判断当前创建的Bean是不是DisposableBean
- 当前Bean是否实现了DisposableBean接口
- 或者,当前Bean是否实现了AutoCloseable接口
- BeanDefinition中是否指定了destroyMethod
- 调用DestructionAwareBeanPostProcessor.requiresDestruction(bean)进行判断
a. ApplicationListenerDetector中直接使得ApplicationListener是DisposableBean
b. InitDestroyAnnotationBeanPostProcessor中使得拥有@PreDestroy注解了的方法就是DisposableBean - 把符合上述任意一个条件的Bean适配成DisposableBeanAdapter对象,并存入disposableBeans中(一个LinkedHashMap)
2.1 什么是DisposableBean接口
在Spring框架中,DisposableBean是一个接口,它定义了一个单一的方法destroy,用于在Spring容器关闭时或一个由Spring管理的Bean不再需要时执行特定的清理操作。当一个Bean实现了DisposableBean接口,Spring容器会在销毁该Bean之前调用其destroy()方法。
2.1.1DisposableBean接口代码
public interface DisposableBean {void destroy() throws Exception;}
2.1.2 DisposableBean接口实现类的代码

2.1.3测试 在容器关闭的时候,会调用close方法

2.2 什么AutoCloseable接口 其实也实现了close方法
AutoCloseable意为可自动关闭的
但是AutoCloseable的代码比较复杂,就不写了
2.2.1AutoCloseable接口的实现类
class MyResource implements AutoCloseable {@Overridepublic void close() throws Exception {System.out.println(0);/*关闭资源*/}
}
2.3 指定了destroyMethod是什么意思啊?
2.3.1
添加了@PreDestroy ,@PreDestroy注解用于在Bean销毁前执行清理操作。在方法上添加@PreDestroy注解后,Spring容器会在Bean销毁前自动调用该方法,以完成清理工作。

2.3.2
自定义的方法名字,Spring会将此方法的名字作为销毁方法的名字
@Component
public class MyMergedBeanDefinitionPostProcessor1 implements MergedBeanDefinitionPostProcessor {@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {if (beanName.equals("xxx")) {//自定义销毁方法的名字beanDefinition.setDestroyMethodName("a");}}public void a(){}
}
2.4判断 调用DestructionAwareBeanPostProcessor.requiresDestruction(bean)进行判断
2.4.1 在docreatebean方法中
// Register bean as disposable.
try {registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}return exposedObject;
2.4.1.1 registerDisposableBeanIfNecessary方法
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {if (mbd.isSingleton()) {// Register a DisposableBean implementation that performs all destruction// work for the given bean: DestructionAwareBeanPostProcessors,// DisposableBean interface, custom destroy method.registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));}else {// A bean with a custom scope...Scope scope = this.scopes.get(mbd.getScope());if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");}scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));}}
}
2.4.1.1.1 requiresDestruction方法判断: 这个方法是重点
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||(hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessorCache().destructionAware))));
}
其中第一个判断方法:
2.4.1.1.1.1 DisposableBeanAdapter.hasDestroyMethod 方法:
bean对象是不是实现了DisposableBean 接口 和AutoCloseable 接口
public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {return true;}return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
}
2.4.1.1.1.1.1
其中的inferDestroyMethodIfNecessary方法:判断是不是有指定的destroymethod
private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {String destroyMethodName = beanDefinition.resolvedDestroyMethodName;if (destroyMethodName == null) {destroyMethodName = beanDefinition.getDestroyMethodName(); //if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||(destroyMethodName == null && bean instanceof AutoCloseable)) {// Only perform destroy method inference or Closeable detection// in case of the bean not explicitly implementing DisposableBeandestroyMethodName = null;if (!(bean instanceof DisposableBean)) {try {destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();}catch (NoSuchMethodException ex) {try {destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();}catch (NoSuchMethodException ex2) {// no candidate destroy method found}}}}beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");}return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
}
2.4.1.1.1.1.1.1 beanDefinition.resolvedDestroyMethodName是一个变量
@Nullablevolatile String resolvedDestroyMethodName;
2.4.1.1.1.1.1.2 getDestroyMethodName方法
这个一般和MergedBeanDefinitionPostProcess接口一起使用
@Nullablepublic String getDestroyMethodName() {return this.destroyMethodName;}
一般在MergedBeanDefinitionPostProcess接口实现类中使用setDestroyMethodName方法:
@Component
public class User implements MergedBeanDefinitionPostProcessor {@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {beanDefinition.setDestroyMethodName("a");}
}
2.4.1.1.1.1.1.3 AbstractBeanDefinition.INFER_METHOD变量
这里特指在beanDefinition.setDestroyMethodName设定(inferred)
常量,表示容器应该尝试推断bean的销毁方法名称,而不是显式指定方法名称。
public static final String INFER_METHOD = "(inferred)";
举例:在MergedBeanDefinitionPostProcess接口实现类中使用setDestroyMethodName方法
@Component
public class MyMergedBeanDefinitionPostProcessor1 implements MergedBeanDefinitionPostProcessor {@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {if (beanName.equals("xxx")) {//设置Spring指定的特定的名字"(inferred)"beanDefinition.setDestroyMethodName("(inferred)");、//自定义销毁方法的名字beanDefinition.setDestroyMethodName("customDestory");}}}
2.4.1.1.1.1.1.3.1 CLOSE_METHOD_NAM变量
指定了特定的销毁方法的名字:“(inferred)”,则会将该Bean中close()和shutdown()作为销毁方法(前提是Bean里面有这两个方法)
private static final String CLOSE_METHOD_NAME = "close";
bean.getClass().getMethod(CLOSE_METHOD_NAME).getName()
2.4.1.1.1.1.1.3.2 CLOSE_METHOD_NAM变量
第二个方法:
2.4.1.1.1.2 hasDestructionAwareBeanPostProcessors 方法:判断有无实现DestructionAwareBeanPostProcessor
protected boolean hasDestructionAwareBeanPostProcessors() {return !getBeanPostProcessorCache().destructionAware.isEmpty();}
2.4.1.1.1.2.1 补充知识 DestructionAwareBeanPostProcessor接口
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {//postProcessBeforeDestruction方法用来进行销毁前置处理,做完这个方法后,调用close方法void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;//requiresDestruction方法是用来筛选哪些bean可以执行postProcessBeforeDestruction方法。default boolean requiresDestruction(Object bean) {return true;}}
2.4.1.1.1.2.2 getBeanPostProcessorCache()方法获取存储PostProcessor的对象,判断其中的destructionAware集合是不是空
BeanPostProcessorCache getBeanPostProcessorCache() {BeanPostProcessorCache bpCache = this.beanPostProcessorCache;if (bpCache == null) {bpCache = new BeanPostProcessorCache();for (BeanPostProcessor bp : this.beanPostProcessors) {if (bp instanceof InstantiationAwareBeanPostProcessor) {bpCache.instantiationAware.add((InstantiationAwareBeanPostProcessor) bp);if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {bpCache.smartInstantiationAware.add((SmartInstantiationAwareBeanPostProcessor) bp);}}if (bp instanceof DestructionAwareBeanPostProcessor) {bpCache.destructionAware.add((DestructionAwareBeanPostProcessor) bp);}if (bp instanceof MergedBeanDefinitionPostProcessor) {bpCache.mergedDefinition.add((MergedBeanDefinitionPostProcessor) bp);}}this.beanPostProcessorCache = bpCache;}return bpCache;}
第三个方法:
2.4.1.1.1.3 DisposableBeanAdapter.hasApplicableProcessors 方法
本质 调用DestructionAwareBeanPostProcessor 的requiresDestruction方法
public static boolean hasApplicableProcessors(Object bean, List<DestructionAwareBeanPostProcessor> postProcessors) {if (!CollectionUtils.isEmpty(postProcessors)) {for (DestructionAwareBeanPostProcessor processor : postProcessors) {if (processor.requiresDestruction(bean)) {return true;}}}return false;}
2.4.1.2 registerDisposableBean方法
对需要销毁的Bean,封装成DisposableBeanAdapter对象,最后调用registerDisposableBean()方法将DisposableBeanAdapter对象放入disposableBeans
public void registerDisposableBean(String beanName, DisposableBean bean) {synchronized (this.disposableBeans) {this.disposableBeans.put(beanName, bean);}}
2.4.1.2.1 disposableBeans 是存放要销毁的bean的集合
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
2.4.1.2.2 DisposableBeanAdapter 对象
这里涉及到一个设计模式:适配器模式 ,在销毁时,Spring会找出定义了销毁逻辑的Bean。 但是我们在定义一个Bean时,如果这个Bean实现了DisposableBean接口,或者实现了 AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么这个Bean都属 于“DisposableBean”,这些Bean在容器关闭时都要调用相应的销毁方法。 所以,这里就需要进行适配,将实现了DisposableBean接口、或者AutoCloseable接口等适配成实现了DisposableBean接口,所以就用到了DisposableBeanAdapter。
class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,List<DestructionAwareBeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {Assert.notNull(bean, "Disposable bean must not be null");this.bean = bean;this.beanName = beanName;this.invokeDisposableBean =(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();this.acc = acc;String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {this.destroyMethodName = destroyMethodName;Method destroyMethod = determineDestroyMethod(destroyMethodName);if (destroyMethod == null) {if (beanDefinition.isEnforceDestroyMethod()) {throw new BeanDefinitionValidationException("Could not find a destroy method named '" +destroyMethodName + "' on bean with name '" + beanName + "'");}}else {if (destroyMethod.getParameterCount() > 0) {Class<?>[] paramTypes = destroyMethod.getParameterTypes();if (paramTypes.length > 1) {throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +beanName + "' has more than one parameter - not supported as destroy method");}else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +beanName + "' has a non-boolean parameter - not supported as destroy method");}}destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);}this.destroyMethod = destroyMethod;}this.beanPostProcessors = filterPostProcessors(postProcessors, bean);}相关文章:
java spring 09 Bean的销毁过程 上 在docreatebean中登记要销毁的bean
1.Bean销毁是发送在Spring容器关闭过程中的 AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);UserService userService (UserService) context.getBean("userService");userService.test();// 容器关闭cont…...
杰发科技AC7801——支持的纠错功能
1. 复位寄存器保留复位类型 低压检测复位(LVD Reset) 集成了一个低压保护系统,以便在电源电压发生变化期间保护存储器内容和控制 MCU 系统状态。该系统由上电复位(POR)电路和 LVD 电路组成,LVD 可以配置为不同的复位基准&#x…...
spring boot运行过程中动态加载Controller
1.被加载的jar代码 package com.dl;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication public class App {public static void main(String[] args) {SpringApplication.run(A…...
学习软考----数据库系统工程师25
关系规范化 1NF(第一范式) 2NF(第二范式) 3NF(第三范式) BCNF(巴克斯范式) 4NF(第四范式) 总结...
RTMP 直播推流 Demo(一)—— 项目配置与视频预览
音视频编解码系列目录: Android 音视频基础知识 Android 音视频播放器 Demo(一)—— 视频解码与渲染 Android 音视频播放器 Demo(二)—— 音频解码与音视频同步 RTMP 直播推流 Demo(一)—— 项目…...
安卓获取SHA
1:安卓通过签名key获取SHA 方式有两种, 1、电脑上来存在eclipse的用户或正在使用此开发工具的用户就简单了,直接利用eclipse 走打包流程,再打包的时候选择相应的签名,那么在当前面板的下面便会出现签名的相关信息。 2、…...
【Qt 学习笔记】Qt常用控件 | 输入类控件 | Dial的使用及说明
博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Qt常用控件 | 输入类控件 | Dial的使用及说明 文章编号:Qt…...
【C语言】项目实践-贪吃蛇小游戏(Windows环境的控制台下)
一.游戏要实现基本的功能: • 贪吃蛇地图绘制 • 蛇吃食物的功能 (上、下、左、右方向键控制蛇的动作) • 蛇撞墙死亡 • 蛇撞自身死亡 • 计算得分 • 蛇身加速、减速 • 暂停游戏 二.技术要点 C语言函数、枚举、结构体、动态内存管…...
在做题中学习(50):搜索插入位置
35. 搜索插入位置 - 力扣(LeetCode) 解法:二分查找 思路:题目是有序的,时间复杂度O(logN),二分没跑了,题目说如果找不到target,返回它应该被插入位置的下标,所以可以分析一下示例2&…...
【mysql】mysql单表查询、多表查询、分组查询、子查询等案例详细解析
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
【Gateway远程开发】0.5GB of free space is necessary to run the IDE.
【Gateway远程开发】0.5GB of free space is necessary to run the IDE. 报错 0.5GB of free space is necessary to run the IDE. Make sure that there’s enough space in following paths: /root/.cache/JetBrains /root/.config/JetBrains 原因 下面两个路径的空间不…...
普通组件的注册-局部注册和全局注册
目录 一、局部注册和全局注册-概述 二、局部注册的使用示例 三、全局注册的使用示例 一、局部注册和全局注册-概述 组件注册有两种方式: 局部注册:只能在注册的组件内使用。使用方法:创建.vue文件,在使用的组件内导入并注册。…...
Apache Dubbo知识点表格总结
Dubbo是一个高性能的Java RPC框架,它提供了一系列的功能来支持分布式系统的开发。通常用于微服务之间的服务调用,顺便提一下也是用于微服务之间调用的OpenFeign,OpenFeign是Spring Cloud体系中的一个声明式HTTP客户端,用于简化HTT…...
电路板/硬件---器件
电阻 电阻作用 电阻在电路中扮演着重要的角色,其作用包括: 限制电流:电阻通过阻碍电子流动的自由而限制电流。这是电阻最基本的功能之一。根据欧姆定律,电流与电阻成正比,电阻越大,通过电阻的电流就越小。…...
STC15W1K16S和VC6.0串口通讯收发测试实例
/********************************************* STC USB 串口板 2014 4 7 20:12 发送接收数据 使用STC串口调试助手通讯正常,L161 **********************************************/ #include "reg51.h" #include "intrins.h" #define…...
Python程序设计 函数(三)
练习十一 函数 第1关: 一元二次方程的根 定义一个函数qg,输入一元二次方程的系数a,b,c 当判别式大于0,返回1和两个根 当判别式等于0,返回0和两个根 当判别式小于0,访问-1和两个根 在主程序中,根据函数返回…...
linux之ssh
SSH远程连接协议 SSH远程管理 定义 SSH(Secure Shell )是一种安全通道协议,主要用来实现字符界面的远程的登录、远程复制等功能。 SSH协议对通信双方的数据传输进行了加密处理,其中包括用户登录时输入的用户口令。因此SSH协议具…...
excel如何将多列数据转换为一列?
这个数据整理借用数据透视表也可以做到: 1.先将数据源的表头补齐,“姓名” 2.点击插入选项卡,数据透视表,在弹出对话框中,数据透视位置选择 现有工作表,(实际使用时新建也没有问题)…...
【Java 刷题记录】前缀和
前缀和 25. 一维前缀和 示例1: 输入: 3 2 1 2 4 1 2 2 3输出: 3 6import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(S…...
NVIDIA: RULER新测量方法让大模型现形
1 引言 最近在人工智能系统工程和语言模型设计方面的进展已经实现了语言模型上下文长度的高效扩展。以前的工作通常采用合成任务,如密钥检索和大海捞针来评估长上下文语言模型(LMs)。然而,这些评估在不同工作中使用不一致,仅揭示了检索能力,无法衡量其他形式的长上下文理解。 …...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...
