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

Spring-bean销毁

bean销毁(找到销毁的bean)

在bean的声明周期中,存在一个记录bean销毁方法的阶段,以备于spring关闭的时候可以执行bean的销毁方法(单例bean)

v1.0 registerDisposableBeanIfNecessary
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);//当rootBeanDefinition不是原型bean,并且requiresDestruction方法返回true代表当前bean是需要销毁的if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {if (mbd.isSingleton()) {//最终通过适配器模式将销毁方法存入disposableBeans这个Map中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));}}}

v1.1 requiresDestruction
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {//首先bean不能为NULLBEAN,然后(实现了DisposableBean接口或实现了AutoCloseable) 或者有销毁的方法return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||(hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessorCache().destructionAware))));}

v1.2 hasDestroyMethod
public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {//如果实现了DisposableBean接口或实现了AutoCloseable,直接返回trueif (bean instanceof DisposableBean || bean instanceof AutoCloseable) {return true;}return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;}private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {//从缓存中获取当前RootBeanDefinition的结束方法String destroyMethodName = beanDefinition.resolvedDestroyMethodName;if (destroyMethodName == null) {//如果缓存中没有,则尝试直接获取销毁方法名称destroyMethodName = beanDefinition.getDestroyMethodName(); ////判断bean销毁的名字是否等于(inferred)或者实现了AutoCloseable接口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;//进入这一阶段,spring会自己去寻找销毁方法if (!(bean instanceof DisposableBean)) {try {//获取类中的close方法destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();}catch (NoSuchMethodException ex) {try {//获取类中的SHUTDOWN_METHOD_NAME方法destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();}catch (NoSuchMethodException ex2) {// no candidate destroy method found}}}}//将销毁方法名字缓存到resolvedDestroyMethodName字段中beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");}return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);}
v1.3 hasDestructionAwareBeanPostProcessors
//判断destructionAware缓存是否为空
protected boolean hasDestructionAwareBeanPostProcessors() {return !getBeanPostProcessorCache().destructionAware.isEmpty();}BeanPostProcessorCache getBeanPostProcessorCache() {//先从缓存中拿取 BeanPostProcessorCache ,如果没获取到,说明还没有对beanPostProcessors进行分类BeanPostProcessorCache bpCache = this.beanPostProcessorCache;if (bpCache == null) {bpCache = new BeanPostProcessorCache();//对所有的beanPostProcessors进行循环分类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;}
v1.4 DisposableBeanAdahasApplicableProcessorspter.
	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;}public boolean requiresDestruction(Object bean) {return findLifecycleMetadata(bean.getClass()).hasDestroyMethods();}private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {if (this.lifecycleMetadataCache == null) {// Happens after deserialization, during destruction...return buildLifecycleMetadata(clazz);}// Quick check on the concurrent map first, with minimal locking.LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);if (metadata == null) {synchronized (this.lifecycleMetadataCache) {metadata = this.lifecycleMetadataCache.get(clazz);if (metadata == null) {metadata = buildLifecycleMetadata(clazz);this.lifecycleMetadataCache.put(clazz, metadata);}return metadata;}}return metadata;}private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {return this.emptyLifecycleMetadata;}//此处使用了双层循环处理//该集合定义了所有的初始化方法List<LifecycleElement> initMethods = new ArrayList<>();//该集合中定义了所有的销毁方法List<LifecycleElement> destroyMethods = new ArrayList<>();Class<?> targetClass = clazz;do {final List<LifecycleElement> currInitMethods = new ArrayList<>();final List<LifecycleElement> currDestroyMethods = new ArrayList<>();ReflectionUtils.doWithLocalMethods(targetClass, method -> {//判断方法是否实现了@PostConstruct注解if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {LifecycleElement element = new LifecycleElement(method);currInitMethods.add(element);if (logger.isTraceEnabled()) {logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);}}//判断方法是否实现了@PreDestroy注解if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {currDestroyMethods.add(new LifecycleElement(method));if (logger.isTraceEnabled()) {logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);}}});//将父类的初始化方法放在最前面initMethods.addAll(0, currInitMethods);//将父类的销毁方法放在最后面destroyMethods.addAll(currDestroyMethods);//获取父类targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :new LifecycleMetadata(clazz, initMethods, destroyMethods));}

执行bean销毁

v1.1 destroySingletons
//销毁单例beanpublic void destroySingletons() {if (logger.isTraceEnabled()) {logger.trace("Destroying singletons in " + this);}synchronized (this.singletonObjects) {this.singletonsCurrentlyInDestruction = true;}String[] disposableBeanNames;synchronized (this.disposableBeans) {//获取所有有销毁方法的bean的名字disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());}//遍历销毁所有的方法for (int i = disposableBeanNames.length - 1; i >= 0; i--) {destroySingleton(disposableBeanNames[i]);}this.containedBeanMap.clear();this.dependentBeanMap.clear();this.dependenciesForBeanMap.clear();clearSingletonCache();}public void destroySingleton(String beanName) {// Remove a registered singleton of the given name, if any.// 先从单例池中移除掉removeSingleton(beanName);// Destroy the corresponding DisposableBean instance.DisposableBean disposableBean;synchronized (this.disposableBeans) {disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);}destroyBean(beanName, disposableBean);}

v1.1 destroyBean
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {// dependentBeanMap表示某bean被哪些bean依赖了// 所以现在要销毁某个bean时,如果这个Bean还被其他Bean依赖了,那么也得销毁其他Bean// Trigger destruction of dependent beans first...Set<String> dependencies;synchronized (this.dependentBeanMap) {// Within full synchronization in order to guarantee a disconnected Setdependencies = this.dependentBeanMap.remove(beanName);}if (dependencies != null) {if (logger.isTraceEnabled()) {logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);}for (String dependentBeanName : dependencies) {destroySingleton(dependentBeanName);}}// Actually destroy the bean now...if (bean != null) {try {bean.destroy();}catch (Throwable ex) {if (logger.isWarnEnabled()) {logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);}}}// Trigger destruction of contained beans...Set<String> containedBeans;synchronized (this.containedBeanMap) {// Within full synchronization in order to guarantee a disconnected SetcontainedBeans = this.containedBeanMap.remove(beanName);}if (containedBeans != null) {for (String containedBeanName : containedBeans) {destroySingleton(containedBeanName);}}// Remove destroyed bean from other beans' dependencies.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();}}}// Remove destroyed bean's prepared dependency information.this.dependenciesForBeanMap.remove(beanName);}

相关文章:

Spring-bean销毁

bean销毁(找到销毁的bean) 在bean的声明周期中&#xff0c;存在一个记录bean销毁方法的阶段&#xff0c;以备于spring关闭的时候可以执行bean的销毁方法&#xff08;单例bean&#xff09; v1.0 registerDisposableBeanIfNecessary protected void registerDisposableBeanIfNec…...

【4】BlazorUI库

【4】BlazorUI库 一、Blazorise二、Ant Design Blazor三、Radzen Blazo四、Radzen Blazo 一、Blazorise Blazorise Blazorise 是一个广泛使用的 UI 框架&#xff0c;提供了丰富的组件库和多个主题支持&#xff0c;如 Bootstrap、Bulma、Material 和 AntDesign。 二、Ant Desig…...

树与二叉树【下】

目录 三. 哈夫曼树3.1 带权路径长度3.2 哈夫曼树的定义3.3 哈夫曼树的构造3.4 哈夫曼编码&#xff08;经常考察&#xff09; 四. 并查集4.1 如何表示“集合”关系&#xff1f;4.2 “并查集”的代码实现4.3 “并查集”的优化4.4 “并查集”的进一步优化 \quad 三. 哈夫曼树 \qua…...

ElementPlus 中el-select自定义指令实现触底加载请求options数据

1) 背景: 老项目翻新时&#xff0c;发现一个下拉框数据非常多&#xff0c;客户呢&#xff0c;希望全部数据一起展示&#xff0c;意思就是全部数据一起返回给前端用于展示。但这会造成明显的卡顿。~~明显的不合理! QAQ!~~ 于是压力给到前端&#xff0c;查询资料&#xff0c;各种…...

基于Selenium实现操作网页及操作windows桌面应用

Selenium操作Web页面 Why? 通常情况下&#xff0c;网络安全相关领域&#xff0c;更多是偏重于协议和通信。但是&#xff0c;如果协议通信过程被加密或者无法了解其协议构成&#xff0c;是无法直接通过协议进行处理。此时&#xff0c;可以考虑模拟UI操作&#xff0c;进而实现相…...

科普文:linux系列之操作系统内存管理简介

概叙 操作系统内存管理是计算机系统中的核心技术之一&#xff0c;页式管理、段式管理和段页式管理各有优缺点。页式管理通过固定大小的页框减少了外部碎片&#xff0c;但可能导致内部碎片&#xff1b;段式管理符合程序逻辑&#xff0c;提供了灵活的内存保护&#xff0c;但可能…...

【已解决】关于MyBatis的collection集合中只能取到一条数据的问题

一、问题 在涉及多表查询的时候&#xff0c;使用collection元素来映射集合属性时&#xff0c;出现了只能查询到一条数据的情况&#xff0c;但用sql语句在数据库中查询会有多条记录。 二、原因 如果两表联查&#xff0c;主表和明细表的主键都是id的话&#xff0c;明细表的多条…...

前端的学习-CSS(弹性布局-flex)

一&#xff1a;什么是弹性布局-Flex flex 是 Flexible Box 的缩写&#xff0c;意为"弹性布局"&#xff0c;用来为盒状模型提供最大的灵活性。 语法&#xff1a; .box{display: flex; } .box{display: inline-flex; } 注意&#xff0c;设为 Flex 布局以后&#xff0…...

vue3集成LuckySheet实现导入本地Excel进行在线编辑,以及导出功能

第一步&#xff1a;克隆或者下载下面的代码 git clone https://github.com/dream-num/Luckysheet.git第二步&#xff1a;安装依赖 npm install npm install gulp -g 第三步&#xff1a;运行 npm run dev效果如下图所示 第四步&#xff1a;打包 打包执行成功后&#xff0c;…...

【征求意见】同济大学--城镇给水厂碳排放核算与评价方法

城镇给水厂保障城镇居民正常生活&#xff0c;是社会经济良性发展的重要基础性设施&#xff0c;对于我国双碳战略目标的实现至关重要。 随着城镇化的发展&#xff0c;城镇供水量不断升高&#xff0c;加上 水资源与生态环境问题不断涌现&#xff0c;人们对水的安全和品质的需求日…...

【Python】后台开发返回方法和状态码类的实现

Python 后台开发中&#xff0c;获取返回的类方法&#xff0c;以及状态码类的实现 代码备份 Code - response.py """ Response class for quick generate response """ from loguru_logger import get_loggerlogger get_logger(__name__)clas…...

opencloudosV8.6和openEuler 24安装 k8s

在三台机器上部署 Kubernetes 集群 1.环境准备2.在所有节点上进行以下步骤1. 更新系统和安装必要的软件包2. 禁用交换分区3. 禁用防火墙和SElinux4.系统主机名5.设置主机名与IP地址解析6.配置内核转发及网桥过滤7. 配置 Docker Cgroup 驱动8. 添加 Kubernetes 仓库并安装 kubea…...

Tensor安装和测试

1: 打开git官方 https://github.com/NVIDIA/TensorRT 2: 下载得到&#xff1a;TensorRT-10.2.0.19.Linux.x86_64-gnu.cuda-11.8.tar.gz 3: 下载后配置环境变量&#xff0c;上面地址记得改成真实地址。 4: 如果想python使用tensorrt&#xff0c;那么 解压后目录&#xff0c…...

ELK对业务日志进行收集

ELK对业务日志进行收集 下载httpd 进到文件设置收集httpd的文件进行 设置 编辑内容 用于收集日志的内容 将日志的内容发送到实例当中 input {file{path > /etc/httpd/logs/access_logtype > "access"start_position > "beginning"}file{path &g…...

新质生产力

新质生产力”是一个相对较新的概念&#xff0c;指的是在数字化、智能化背景下&#xff0c;依托新技术、新业态、新模式&#xff0c;提升生产力质量和效率的一种生产力形态。它强调的是技术和创新对生产力的提升作用&#xff0c;尤其是在人工智能、大数据、互联网等新兴技术的推…...

《LeetCode热题100》---<5.②普通数组篇五道>

本篇博客讲解LeetCode热题100道普通数组篇中的六道题 第三道&#xff1a;轮转数组&#xff08;中等&#xff09; 第四道&#xff1a;除自身以外数组的乘积&#xff08;中等&#xff09; 第三道&#xff1a;轮转数组&#xff08;中等&#xff09; 方法一&#xff1a;使用额外的数…...

【面试题】【C语言】寻找两个正序数组的中位数

寻找两个正序数组的中位数 仅供学习 题目 算法时间复杂度 二分查找算法&#xff0c;时间复杂度为 O(log(min(m, n)))&#xff0c;其中 m 和 n 分别是两个数组的长度。 子函数 查找两个数字的最大值 int max(int a, int b) {return a > b ? a : b; }查找两个数字的最小…...

原始的原型链是怎样玩的

带着问题看代码&#xff1a; 1、原始的继承是怎样实现继承的&#xff1f; A类的prototype 属性 B类的实例 2、实现继承后&#xff0c;连B类的中实例的属性&#xff08;放在了A类的prototype中&#xff09;和原型链的上的东西都可以用 3、A.prototype.constructor实际上已经指向…...

RabbitMQ高级篇(如何保证消息的可靠性、如何确保业务的幂等性、延迟消息的概念、延迟消息的应用)

文章目录 1. 消息丢失的情况2. 生产者的可靠性2.1 生产者重连2.2 生产者确认2.3 生产者确认机制的代码实现2.4 如何看待和处理生产者的确认信息 3. 消息代理&#xff08;RabbitMQ&#xff09;的可靠性3.1 数据持久化3.2 LazyQueue&#xff08; 3.12 版本后所有队列都是 Lazy Qu…...

正点原子imx6ull-mini-Linux驱动之platform设备驱动实验(14)

我们在前面几章编写的设备驱动都非常的简单&#xff0c;都是对IO进行最简单的读写操作像I2C、 SPI、LCD 等这些复杂外设的驱动就不能这么去写了&#xff0c;Linux 系统要考虑到驱动的可重用性&#xff0c;因此提出了驱动的分离与分层这样的软件思路&#xff0c;在这个思路下诞生…...

如何快速恢复加密压缩包密码:ArchivePasswordTestTool完整指南

如何快速恢复加密压缩包密码&#xff1a;ArchivePasswordTestTool完整指南 【免费下载链接】ArchivePasswordTestTool 利用7zip测试压缩包的功能 对加密压缩包进行自动化测试密码 项目地址: https://gitcode.com/gh_mirrors/ar/ArchivePasswordTestTool 你是否曾经遇到过…...

为AI智能体构建可编程邮箱:mailbot实战指南

1. 项目概述&#xff1a;为AI智能体打造专属的“可编程邮箱”如果你正在开发一个AI智能体&#xff0c;无论是客服机器人、自动化工作流还是个人助理&#xff0c;让它具备收发邮件的能力往往是刚需。传统的做法是什么&#xff1f;要么去折腾Gmail的API&#xff0c;忍受OAuth授权…...

Windows内核级虚拟串口驱动com0com:构建无限虚拟COM端口对的终极解决方案

Windows内核级虚拟串口驱动com0com&#xff1a;构建无限虚拟COM端口对的终极解决方案 【免费下载链接】com0com Null-modem emulator - The virtual serial port driver for Windows. Brought to you by: vfrolov [Vyacheslav Frolov](http://sourceforge.net/u/vfrolov/profil…...

Google 2026 AI全家桶升级:企业管理员必须在48小时内完成的3项策略校准与2项合规备案

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Google 2026 AI全家桶升级全景图 2026年&#xff0c;Google正式发布新一代AI基础设施矩阵——“Project Aether”&#xff0c;标志着其AI全家桶从模块化协同迈向原生融合时代。核心升级聚焦于模型、工具…...

基于OpenClaw的GitHub趋势智能监控器:自动化追踪与AI摘要推送

1. 项目概述&#xff1a;一个为开发者打造的GitHub趋势智能监控器 作为一名长期泡在GitHub上的开发者&#xff0c;我深知每天手动刷“Trending”页面有多低效。热门项目层出不穷&#xff0c;但真正值得关注的往往就那么几个&#xff0c;而且很容易被淹没在信息流里。直到我遇到…...

OpenClaw用户如何快速接入Taotoken并配置自定义模型提供方

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 OpenClaw用户如何快速接入Taotoken并配置自定义模型提供方 对于使用OpenClaw这类Agent工具的开发者而言&#xff0c;直接利用Taoto…...

Unity3D游戏马赛克清除终极指南:7种高效技术深度解析

Unity3D游戏马赛克清除终极指南&#xff1a;7种高效技术深度解析 【免费下载链接】UniversalUnityDemosaics A collection of universal demosaic BepInEx plugins for games made in Unity3D engine 项目地址: https://gitcode.com/gh_mirrors/un/UniversalUnityDemosaics …...

从平面到立体:基于OpenLayers与Cesium的无缝地图维度切换实践

1. 二维与三维地图融合的必要性 在现代WebGIS开发中&#xff0c;单纯依赖二维地图已经难以满足用户对空间数据展示的需求。想象一下&#xff0c;当你查看一个城市规划系统时&#xff0c;平面地图能告诉你道路走向&#xff0c;但只有切换到三维视图才能直观看到建筑高度、地形起…...

Mac Mouse Fix终极指南:如何让普通鼠标在Mac上获得超越触控板的体验

Mac Mouse Fix终极指南&#xff1a;如何让普通鼠标在Mac上获得超越触控板的体验 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix 还在为Mac上第三…...

2023B卷,阿里巴巴找黄金宝箱(4)

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:华为OD面试 文章目录 一、🍀前言 1.1 ☘️题目详情 1.2 ☘️参考解题答案 一、🍀前言 2023B卷,阿里巴巴找黄金宝箱(4)。 1.1 ☘️题目详情 题目:…...