当前位置: 首页 > 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;在这个思路下诞生…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

【51单片机】4. 模块化编程与LCD1602Debug

1. 什么是模块化编程 传统编程会将所有函数放在main.c中&#xff0c;如果使用的模块多&#xff0c;一个文件内会有很多代码&#xff0c;不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里&#xff0c;在.h文件里提供外部可调用函数声明&#xff0c;其他.c文…...