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

news2024/11/25 7:30:10

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/1652602.html

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

相关文章

2W 6KVDC 隔离双输出 DC/DC 电源模块——TPJ-2W 系列

TPJ-2W一款有超高隔离电压的电源模块&#xff0c;主要用于隔离度要求高的如医疗仪器和设备&#xff0c;特别在安全设备的应用中起着相当重要的作用&#xff0c;它的绝缘设计完全能满足对隔离电压要求超过6KVDC的应用&#xff0c;在额定负载2W的情况下&#xff0c;工作温度范围为…

基于springboot实现夕阳红公寓管理系统项目【项目源码+论文说明】

基于springboot实现夕阳红公寓管理系统演示 摘要 如今社会上各行各业&#xff0c;都在用属于自己专用的软件来进行工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。互联网的发展&#xff0c;离不开一些新的技术&#xff0c;而新技术的产生往往是…

ES6-自学01

调用方法读取文件&#xff1a;如果失败就throw抛出err,成功则抛出data 2.使用promise封装&#xff0c;如果失败就改变状态为 reject(err) 如果成功就 resolve(返回成功的值) &#xff0c;然后then,就可以获取返回的值&#xff0c;值toString&#xff08;&#xff09;方法来把…

ShowMeAI | 这是我们知道的,关于〖Suno 〗和〖AI音乐〗的一切

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; Suno 是一款AI音乐创作工具&#xff0c;可以通过提示词和设置生成一段音乐&#xff0c;而且可以包含歌词和人声 (这非常难得)。在经历了两年探索之后…

银河麒麟QT项目打包详细教程

银河麒麟QT项目打包详细教程 一、QT项目打包 下载linuxdeployqt&#xff0c;下载地址&#xff1a;https://github.com/probonopd/linuxdeployqt/releases 安装Linuxdeployqt 2.1 为了安装方便&#xff0c;将下载下来的文件名称改短些 mv linuxdeployqt-6-x86_64.AppImage lin…

zer0pts CTF 2022 -- kRCE

文章目录 前言题目分析漏洞利用提权shell exp 前言 这道题目非常有意思&#xff0c;看似 kernel pwn&#xff0c;但又是一个非常规的 kernel pwn&#xff0c;通过这个题目也学到了很多&#xff0c;这里主要参考 Will’s Root 的 wp 题目分析 作者写了一个具有多个漏洞的驱动…

工厂车间冷风机降温通风措施

冷风机的工作原理主要基于蒸发冷却原理&#xff0c;以下是其具体的工作流程&#xff1a; 空气吸入&#xff1a;当冷风机开始工作时&#xff0c;首先通过风扇将车间内的热空气吸入冷风机的机体内。蒸发冷却&#xff1a;冷风机内部有一个或多个湿帘或水帘&#xff0c;当热空气通…

打破次元壁!Stable Diffusion将现实影像转成二次元动画,推特转赞10k+,网友:都可以重做《神奇宝贝》动漫了

破次元壁计划已启动&#xff01; 就在最近&#xff0c;有网友分享了一个用Stable Diffusion打造二次元动画的工具&#xff0c;直接在网上爆火。 先快来看一波效果。 万物皆可妙化为二次元&#xff0c;耳机也可蜕变成小兔兔&#xff1a; 瞧&#xff01;连易拉罐的拉环也化身成…

数字孪生项目的开发

数字孪生项目开发涉及多学科知识和技术&#xff0c;因此存在以下技术难点&#xff0c;数字孪生项目开发是一项复杂的工程&#xff0c;需要攻克多项技术难关。随着技术的不断发展&#xff0c;数字孪生技术将得到更加广泛的应用&#xff0c;并在各行各业发挥更大的作用。北京木奇…

顶顶通呼叫中心中间件电话黑名单系统介绍

黑名单 有显示成功和失败导入数&#xff0c;可以禁用也可以启用&#xff0c;如果禁用状态就是不使用这一组黑名单&#xff0c;多个号码核验就是验证号码存不存在。黑名单只有管理员和操作员可以配置&#xff0c;租户是看不到黑名单的。但是黑名单跟租户是互通的。 可以单个号码…

windows下安装最新的nginx

1、进入官网下载地址 https://nginx.org/en/download.html#/ 2、点击这里最新的版本下载 3、&#xff08;不要直接运行解压的nginx.exe&#xff09;,应这样操作WindowsR&#xff0c;输入CMD&#xff0c; 4、查看一下自己解压后的位置&#xff0c;我的是在E盘 5、输入对应的W…

ADOP带你了解:长距离 PoE 交换机

您是否知道当今的企业需要的网络连接超出了传统交换机所能容纳的长度&#xff1f;这就是我们在长距离 PoE 交换机方面的专业化变得重要的地方。我们了解扩展网络覆盖范围的挑战&#xff0c;无论是在广阔的园区还是在多栋建筑之间。使用这些可靠的交换机&#xff0c;我们不仅可以…

百川2模型解读

简介 Baichuan 2是多语言大模型&#xff0c;目前开源了70亿和130亿参数规模的模型。在公开基准如MMLU、CMMLU、GSM8K和HumanEval上的评测&#xff0c;Baichuan 2达到或超过了其他同类开源模型&#xff0c;并在医学和法律等垂直领域表现优异。此外&#xff0c;官方还发布所有预…

【编程题-错题集】连续子数组最大和(动态规划 - 线性 dp)

牛客对应题目链接&#xff1a;连续子数组最大和_牛客题霸_牛客网 (nowcoder.com) 一、分析题目 简单线性 dp。 1、状态表示 dp[i] 表示&#xff1a;以 i 位置为结尾的所有子数组中&#xff0c;最大和是多少。 2、状态转移方程 dp[i] max(dp[i - 1] arr[i], arr[i]) 3、返回…

HTML批量文件上传2——进度条显示

作者&#xff1a;私语茶馆 非常多的云应用中需要上传文本&#xff0c;包括图片&#xff0c;文件等等&#xff0c;这些批量文件上传&#xff0c;往往涉及到进度条显示&#xff0c;多文件上传等&#xff0c;这里分享一个非常好的案例&#xff0c;来自BootStrapfriendly.com&#…

6W 1.5KVDC、3KVDC 隔离宽电压输入 DC/DC 电源模块——TP06DA 系列

TP06DA系列电源模块额定输出功率为6W&#xff0c;外形尺寸为31.75*20.32*10.65&#xff0c;应用于2:1及4:1电压输入范围 4.5-9、9V-18V、18V-36V、36V-72V、9V-36V和18V-72VDC的输入电压环境&#xff0c;输出电压精度可达1%&#xff0c;具有输出短路保护等功能&#xff0c;可广…

经验浅谈!伦敦银如何交易?

近期&#xff0c;伦敦银价格出现很强的上涨&#xff0c;这促使一些新手投资者进入了市场&#xff0c;但由于缺乏经验&#xff0c;他们不知道该怎么在市场中交易&#xff0c;下面我们就从宏观上介绍一些方法&#xff0c;来讨论一下伦敦银如何交易。 首先我们要知道&#xff0c;要…

[C/C++] -- 装饰器模式

装饰器模式是一种结构型设计模式&#xff0c;它允许在不改变原始对象的基础上动态地扩展其功能。这种模式通过将对象包装在装饰器类的对象中来实现&#xff0c;每个装饰器对象都包含一个原始对象&#xff0c;并可以在调用原始对象的方法之前或之后执行一些额外的操作。 装饰器…

windows环境下 postgresql v12 绿色版+postgis 3.4.1版本配置,空间数据库迁移

windows环境下 postgresql v12 绿色版+postgis 3.4.1版本配置,空间数据库迁移 一、软件环境 操作系统:windows 11 pg免安装版数据库:postgresql-12.17-1-windows-x64-binaries.zip 下载地址:https://get.enterprisedb.com/postgresql/postgresql-12.18-1-windows-x64-bina…