java spring 10 Bean的销毁过程 上 在docreatebean中登记要销毁的bean

news2025/1/12 20:53:00

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 {
	@Override
	public 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 {
 
	@Override
	public 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 DisposableBean
         destroyMethodName = 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是一个变量

	@Nullable
	volatile String resolvedDestroyMethodName;

2.4.1.1.1.1.1.2 getDestroyMethodName方法
这个一般和MergedBeanDefinitionPostProcess接口一起使用

	@Nullable
	public String getDestroyMethodName() {
		return this.destroyMethodName;
	}

一般在MergedBeanDefinitionPostProcess接口实现类中使用setDestroyMethodName方法:

@Component
public class User implements MergedBeanDefinitionPostProcessor {

	@Override
	public 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 {
 
	@Override
	public 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://www.coloradmin.cn/o/1661067.html

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

相关文章

Java找不到包解决方案

在跟着教程写Spingboot后端项目时&#xff0c;为了加快效率&#xff0c;有时候有的实体文件可以直接粘贴到目录中&#xff0c;此时运行项目会出现Java找不到包的情况&#xff0c;即无法找到导入的实体文件&#xff0c;这是项目没有更新的原因。解决方法&#xff1a; 刷新Maven:…

如何在40分钟之内,又快又准完成四六级阅读柯桥考级英语培训

答题步骤和技巧 1 选词填空 选词填空部分字数在200~300之间&#xff0c;设有10个空&#xff0c;提供15个备选项&#xff0c;从中选出最合适答案。选词填空题相对于普通的完型题简单&#xff0c;但是考察内容基本一致。集中考察的点有语法现象&#xff0c;逻辑衔接和搭配。每空…

纯血鸿蒙APP实战开发——数字滚动动效实现

介绍 本示例主要介绍了数字滚动动效的实现方案。 该方案多用于数字刷新&#xff0c;例如页面刷新抢票数量等场景。 效果图预览 使用说明&#xff1a; 下拉页面刷新&#xff0c;数字进行刷新。 实现思路 通过双重ForEach循环分别横向、纵向渲染数字。 Row() {ForEach(this…

Golang面向对象编程(一)

文章目录 结构体基本介绍结构体定义方式创建结构体变量结构体内存对齐结构体类型转换字段的Tag标签 方法基本介绍方法的定义和调用方法调用的传参机制String方法 结构体 基本介绍 基本介绍 Go支持面向对象编程特性&#xff0c;包括封装、继承和多态&#xff0c;但Go中没有类&a…

Day 29 MySQL的主从复制集群

一&#xff1a;主从复制 1.主从复制概念 什么是主从复制&#xff1a; ​ 主从复制&#xff0c;是用来建立一个和主数据库完全一样的数据库环境&#xff0c;称为从数据库&#xff1b;主数据库一般是准实时的业务数据库 主从复制的作用&#xff1a; ​ 做数据的热备&#xf…

STM32_HAL_RTC_解决恢复电源时再一次初始化

1问题 板子再次恢复电源时直接初始化了时间 2解决思路 在初始化函数&#xff08;MX_RTC_Init();&#xff09;中增加判断&#xff0c;判断是否是二次初始化 将值放入备份存储其中 3问题图 4解决后的源码 /* RTC init function */ void MX_RTC_Init(void) {/* USER CODE BE…

如何查看centos7中Java在哪些路径下

在 CentOS 7 上&#xff0c;你可以通过几种方式查找安装的 Java 版本及其路径。以下是一些常用的方法&#xff1a; 1. 使用 alternatives 命令 CentOS 使用 alternatives 系统来管理同一命令的多个版本。你可以使用以下命令来查看系统上所有 Java 安装的配置&#xff1a; su…

minio安装部署

MinIO 介绍 MinIO是一个对象存储解决方案&#xff0c;它提供了与Amazon Web Services S3兼容的API&#xff0c;并支持所有核心S3功能。 MinIO有能力在任何地方部署 - 公有云或私有云&#xff0c;裸金属基础设施&#xff0c;编排环境&#xff0c;以及边缘基础设施。 MinIO 安装…

如何选择适合自己网站的SSL证书提供商?

在互联网技术飞速发展的今天&#xff0c;确保数据安全已成为网站运营的基石。HTTPS证书作为一项重要的安全认证协议&#xff0c;对于保护数据传输的安全性至关重要。本文将为您提供一份详尽的指南&#xff0c;帮助您了解如何申请和部署HTTPS证书。 一、选择SSL证书提供商 首先…

初阶数据结构—顺序表和链表

第一章&#xff1a;线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就…

快速上手prometheaus grafana 监控

介绍 prometheaus 一个定时输出指标数据的巡检组件&#xff1f; grafana 一个读取指标&#xff0c;可视化的提供了好看界面的组件&#xff1f; 教程 如何和springboot项目集成 【IT老齐153】超级实用&#xff01;十分钟掌握Prometheus与Grafana监控SpringBoot应用_哔哩哔哩_…

TikTok shop多账户需要防关联吗?

TikTok是一个非常垂直的平台&#xff0c;每个账号的内容都应该尽可能的垂直&#xff0c;这样平台才能引流更多的流量。但是&#xff0c;TikTokShop只有一两个账号&#xff0c;流量往往难以保证&#xff0c;所以很多商家选择了TikTok的多账号运营模式。 众所周知&#xff0c;多店…

YOLOv8+PyQt5蔬菜识别检测(26种不同蔬菜类型,yolov8模型,从图像、视频和摄像头三种路径识别检测)

1.基于最新的YOLOv8训练的蔬菜检测模型&#xff0c;和基于PyQt5制作的可视蔬菜检测系统&#xff0c;该系统可自动检测和识别图片或视频当中出现的26种蔬菜&#xff1a;鸡蛋, 姜, 菜椒, 南瓜, 山药, 辣椒, 霉豆, 蘑菇, 香菜, 茼蒿, 油菜, 黄瓜, 角瓜, 莲藕, 西兰花, 菜花, 土豆,…

【网络编程】UDP协议和TCP协议1

UDP协议格式 UDP 报文分为 UDP 报头和 UDP 数据区两部分。报头由 4 个 16 位长&#xff08;2字节&#xff09;字段组成&#xff0c;分别说明该报文的源端口、目的端口、报文长度和校验值。 UDP协议如何将报头和有效载荷分离 UDP报头是一种定长报头&#xff0c;长度为8个字节。…

数控六面钻适用场景-不止家具制造

在快节奏的现代生活中&#xff0c;家具作为我们生活的重要组成部分&#xff0c;其美观度和实用性日益受到人们的关注。而在这背后&#xff0c;一个不可或缺的“工匠”正默默地发挥着它的作用——那就是数控六面钻。 数控六面钻&#xff0c;顾名思义&#xff0c;是一种高度自动…

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

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

JavaScript数字(Number)个数学(Math)对象

目录 前言&#xff1a; Number&#xff08;数字&#xff09;对象 前言&#xff1a; nfinity(正负无穷大)&#xff1a; NaN&#xff08;非数字&#xff09;&#xff1a; Number的属性 Number的方法 构造函数 静态方法 实例方法 Math&#xff08;数学&#xff09;对象…

【hackmyvm】 Animetronic靶机

靶机测试 arp-scanporturl枚举exiftool套中套passwordsudo 提权 arp-scan arp-scan 检测局域网中活动的主机 192.168.9.203 靶机IP地址port 通过nmap扫描&#xff0c;获取目标主机的端口信息 ┌──(root㉿kali)-[/usr/share/seclists] └─# nmap -sT -sV -O 192.16…

Java入门基础学习笔记12——变量详解

变量详解&#xff1a; 变量里的数据在计算机中的存储原理。 二进制&#xff1a; 只有0和1&#xff0c; 按照逢2进1的方式表示数据。 十进制转二进制的算法&#xff1a; 除二取余法。 6是110 13是1101 计算机中表示数据的最小单元&#xff1a;一个字节&#xff08;byte&…

今日arXiv最热NLP大模型论文:NAACL24实锤语言学对大模型“负优化”,抽象语义表示+思维链有损表现

大语言模型正以势不可挡的姿态席卷自然语言处理领域。在这个语言模型大显神威的时代&#xff0c;很多任务都转变为了端到端的文本生成任务。那么&#xff0c;在此之前我们苦心孤诣研究了几十年的语义表示&#xff0c;例如 AMR(抽象意义表示)&#xff0c;在这个时代里还能派上用…