java spring 10 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

  1. 当前Bean是否实现了DisposableBean接口
  2. 或者,当前Bean是否实现了AutoCloseable接口
  3. BeanDefinition中是否指定了destroyMethod
  4. 调用DestructionAwareBeanPostProcessor.requiresDestruction(bean)进行判断
    a. ApplicationListenerDetector中直接使得ApplicationListener是DisposableBean
    b. InitDestroyAnnotationBeanPostProcessor中使得拥有@PreDestroy注解了的方法就是DisposableBean
  5. 把符合上述任意一个条件的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);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3030406.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习Labelme】使用Segment Anything Model (SAM)快速打标,labelme多边形转yolo txt框看看对不对

文章目录 windows安装环境打开labelme自动保存勾选上&#xff0c;保存图片数据不要勾选选SAM精准模型&#xff0c;然后打开图片路径&#xff0c;然后点击创建AI多边形&#xff1a;鼠标点击确认物体控制点&#xff0c;确认完成后&#xff0c;双击鼠标完成选取&#xff0c;并给上…

python之并发编程

python之并发编程 线程的创建方式线程的创建方式(方法包装)线程的创建方式(类包装)join()【让主线程等待子线程结束】守护线程【主线程结束&#xff0c;子线程就结束】 锁多线程操作同一个对象(未使用线程同步)多线程操作同一个对象(增加互斥锁&#xff0c;使用线程同步)死锁案…

P9420 [蓝桥杯 2023 国 B] 子 2023 / 双子数

蓝桥杯2023国B A、B题 A题 分析 dp问题 根据子序列&#xff1a;2&#xff0c;20&#xff0c;202&#xff0c;2023分为4个状态&#xff1b; 当前数字为2时&#xff0c;处于dp[0]&#xff0c;或者和dp[1]结合成dp[2]&#xff1b; 当前数字为0时&#xff0c;和dp[0]结合成dp[…

什么是SOL链跟单机器人与阻击机器人?

SOL链作为一个快速增长的区块链生态系统&#xff0c;为各种应用程序提供了丰富的发展机会。在SOL链上&#xff0c;智能合约的应用已经开始蓬勃发展&#xff0c;其中包括了许多与加密货币交易相关的应用。在本文中&#xff0c;我们将介绍在SOL链上开发的阻击机器人&#xff08;S…

【二叉树算法题记录】二叉树的所有路径,路径总和——回溯

目录 257. 二叉树的所有路径题目描述题目分析cpp代码 112. 路径总和题目描述题目分析cpp代码 257. 二叉树的所有路径 题目描述 给你一个二叉树的根节点root &#xff0c;按任意顺序&#xff0c;返回所有从根节点到叶子节点的路径。 题目分析 其实从根节点往下走&#xff0c…

Mat: Unknown HPROF Version

问题&#xff1a;Mat 加载 android studio 导出的 hprof 文件失败 原因&#xff1a;android hprof 文件不是标准的 java hprof 文件 解决办法&#xff1a; 使用 android sdk 自带的命令将 hprof 转换成标准的 java hprof

替代UCC21550隔离式双通道栅极驱动器

描述 PC86320是一个隔离的双通道栅极驱动器具有可编程死区时间和宽温度范围。它设计有5A峰值源和6A峰值吸收电流来驱动电源高达2MHz的MOSFET、SiC、GaN和IGBT晶体管开关频率。PC86320可以配置为两个低端驱动器&#xff0c;两个高边驱动器&#xff0c;或具有可编程功能的半桥驱…

JavaScript数组(Array)方法 - toReversed、toSorted、toSpliced

最近发现几个数组方法&#xff0c;是一些常规方法的升级版&#xff0c;比较有意思&#xff0c;分享给大家 文章目录 一、温故二、知新toReversedtoSortedtoSpliced 一、温故 我们先来回顾几个比较常用的方法&#xff1a;reverse&#xff0c;sort&#xff0c;splice众所周知&a…

【HMGD】GD32/STM32 DMA接收不定长串口数据

单片机型号&#xff1a;GD32F303系列 CubeMX配置 配置串口参数 开启DMA 开启中断 示例代码 使用到的变量 uint8_t RX_Buff_FLAG 0; uint8_t RX_Buff[300] {0}; uint8_t TX_Buff[300] {0};串口接收空闲函数 // 串口接收空闲函数 void HAL_UARTEx_RxEventCallback(UART_H…

深入理解Java HashSet类及其实现原理

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

伦敦金交易常识 原来可以这样分类

如果投资者想做好伦敦金交易&#xff0c;对市场中的伦敦金交易常识等等都需要加以学习和研究&#xff0c;别小看那些伦敦金交易常识&#xff0c;很多高深的交易策略也是从常识出发慢慢建立起来的。伦敦金交易常识可以分为几类&#xff0c;下面我们就来讨论一下。 伦敦金市场的基…

OpenNJet,够轻更强云原生应用引擎

前言&#xff1a; 在正式介绍OpenNJet之前&#xff0c;我们先来看看它的技术架构&#xff0c;如下图所示&#xff0c;OpenNJet正是NGINX的Pro版&#xff0c;在100%兼容NGINX基础上&#xff0c;新增了动态配置加载、主动式健康检测、集群高可用、声明式API等多种强大功能。 NGIN…

FLEX组件可视化设计器CSS3代码生成器

Flex布局可以简便、完整、响应式地实现各种页面布局&#xff0c;所以本软件研发出来FLEX组件。Flex组件是本软件布局的核心&#xff0c;只有掌握好flex组件布局&#xff0c;你才能打造出优秀的个性化页面。 设计完成后整个布局及CSS样式代码都会生成。 排列方向flex-direction…

GPT+Python近红外光谱数据分析

原文链接&#xff1a;GPTPython近红外光谱数据分析https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247603913&idx1&sn6eb8fd6f1abcdd8160815997a13eb03d&chksmfa82172ecdf59e389a860547a238bb86c7f38ae3baa14e97c7490a52ef2a2c206f88d503a5eb&token…

《星河战队4:星际觉醒》(上)AI科幻电影欣赏

《星河战队4&#xff1a;星际觉醒》&#xff08;上&#xff09;AI科幻电影欣赏 征服与荣耀&#xff0c;贪婪与救赎&#xff0c;浩瀚宇宙&#xff0c;人类终将灭绝&#xff1f; 《星河战队4&#xff1a;星际觉醒》&#xff08;上&#xff09;在未来世界&#xff0c;随着星际探索…

使用LangChain和Neo4j快速创建RAG应用

大家好&#xff0c;Neo4j 通过集成原生的向量搜索功能&#xff0c;增强了其对检索增强生成&#xff08;RAG&#xff09;应用的支持&#xff0c;这标志着一个重要的里程碑。这项新功能通过向量索引搜索处理非结构化文本&#xff0c;增强了 Neo4j 在存储和分析结构化数据方面的现…

Zabbix监控中文乱码问题解决方法

一、问题描述 1.查看Zabbix仪表盘 在Zabbix的监控仪表盘界面&#xff0c;字体显示为“方框”&#xff0c;无法查看到具体的性能指标名称。 2.问题分析 Zabbix的web端没有中文字库&#xff0c;导致切换到中文页面&#xff0c;中文成了乱码这个问题&#xff0c;我们最需要把中文…

Vue2 组件通信方式

props/emit props 作用&#xff1a;父组件通过 props 向子组件传递数据parent.vue <template><div><Son :msg"msg" :pfn"pFn"></Son></div> </template><script> import Son from ./son export default {name: …

RAG 场景对Milvus Cloud向量数据库的需求

虽然向量数据库成为了检索的重要方式,但随着 RAG 应用的深入以及人们对高质量回答的需求,检索引擎依旧面临着诸多挑战。这里以一个最基础的 RAG 构建流程为例:检索器的组成包括了语料的预处理如切分、数据清洗、embedding 入库等,然后是索引的构建和管理,最后是通过 vecto…

【计算机毕业设计】springboot河北任丘非物质文化遗产数字化传承

当今社会进入了科技进步、经济社会快速发展的新时代。国际信息和学术交流也不断加强&#xff0c; 计算机技术对经济社会发展和人民生活改善的影响也日益突出&#xff0c;人类的生存和思考方式也产生了变化。传统购物方式采取了人工的管理方法&#xff0c;但这种管理方法存在着许…