多域名一个网站备案,制作网站品牌公司简介,北京网站建设专家,厦门做网站优化多少钱目录 前言阅读建议 课程内容一、Bean什么时候销毁二、实现自定义的Bean销毁逻辑2.1 实现DisposableBean或者AutoCloseable接口2.2 使用PreDestroy注解2.3 其他方式#xff08;手动指定销毁方法名字#xff09; 三、注册销毁Bean过程及方法详解3.1 AbstractBeanFactory#requir… 目录 前言阅读建议 课程内容一、Bean什么时候销毁二、实现自定义的Bean销毁逻辑2.1 实现DisposableBean或者AutoCloseable接口2.2 使用PreDestroy注解2.3 其他方式手动指定销毁方法名字 三、注册销毁Bean过程及方法详解3.1 AbstractBeanFactory#requiresDestruction需要销毁吗3.2 DisposableBeanAdapter.hasDestroyMethod是否有销毁方法3.3 DisposableBeanAdapter#inferDestroyMethodIfNecessary推断销毁方法3.4 AbstractBeanFactory#hasDestructionAwareBeanPostProcessors是否有感知销毁Bean后置处理器3.5 DisposableBeanAdapter.hasApplicableProcessors是否有应用于当前Bean的销毁感知Bean后置处理器3.6 DefaultSingletonBeanRegistry#registerDisposableBean注册需要销毁的bean3.7 注册销毁Bean过程总结 四、注册销毁Bean逻辑流程图五、概念回顾 学习总结 前言
我们在这里讲的是Bean的销毁过程。也许不少朋友说到Bean的销毁可能会想到垃圾回收的东西。虽然都是在做生命周期的最后一部分但其实这俩不是同一回事。垃圾回收是JVM级别的东西这里说的Bean销毁是Spring的东西所以当然不是一回事。
阅读建议
本节课的内容将会以下面这段代码为入口讲解 // 注册Bean的销毁接口try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, Invalid destruction signature, ex);}return exposedObject;这段代码其实是在Spring实例化里面的AbstractAutowireCapableBeanFactory#doCreateBean()方法里面。而且通过这个方法名字大家也知道了这一步仅仅只是注册销毁逻辑而已并不是真的销毁。只有当一定条件成立的时候才会去销毁。 registerDisposableBeanIfNecessary具体代码如下 /*** 将给定bean添加到此工厂中的一次性bean列表中注册其DisposableBean接口和/或给定的destroy方法以便在工厂关闭时调用(如果适用)。只适用于单例。 * 参数: * beanName—bean的名称—bean实例mbd—bean的bean定义 * 参见: * RootBeanDefinition。isSingleton RootBeanDefinition。getDependsOn, registerDisposableBean, registerDependentBean*/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));}}}课程内容
一、Bean什么时候销毁
Bean销毁是发生在Spring容器关闭过程中。这时Spring所有的单例Bean都会被销毁并且会执行各自实现了自定义销毁逻辑的Bean的销毁方法。我们在本篇文章要介绍的就是如何实现自定义的Bean销毁逻辑。 在Spring容器关闭时可以显示关闭比如
AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService (UserService) context.getBean(userService);
userService.test();// 容器关闭
context.close();又或者注册一个关闭钩子
AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);// 注册关闭钩子
context.registerShutdownHook();Object newUser context.getBean(user);
System.out.println(newUser);【注意强制杀掉进程kill pid是不会调用自定义的Bean销毁逻辑】
Spring关闭容器的过程
首先发布ContextClosedEvent事件调用lifecycleProcessor的onCloese()方法销毁单例Bean 遍历disposableBeans 把每个disposableBean从单例池中移除调用disposableBean的destroy()如果这个disposableBean还被其他Bean依赖了那么也得销毁其他Bean如果这个disposableBean还包含了inner beans将这些Bean从单例池中移除掉 清空manualSingletonNames是一个Set存的是用户手动注册的单例Bean的beanName清空allBeanNamesByType是一个Mapkey是bean类型value是该类型所有的beanName数组清空singletonBeanNamesByType和allBeanNamesByType类似只不过只存了单例Bean
二、实现自定义的Bean销毁逻辑
实现方式有如下几种
2.1 实现DisposableBean或者AutoCloseable接口
需要自定义销毁的Bean代码示例实现自DisposableBean
Component
public class TestDestroyBean implements DisposableBean {public void test() {System.out.println(测试一下销毁方法);}Overridepublic void destroy() throws Exception {System.out.println(TestDestroyBean------自定义的Bean销毁方法);}
}或者实现自AutoCloseable
Component
public class TestDestroyBean implements AutoCloseable {public void test() {System.out.println(测试一下销毁方法);}Overridepublic void close() throws Exception {System.out.println(TestDestroyBean------自定义的Bean销毁方法);}
}2.2 使用PreDestroy注解
实现方式有如下3种
Component
public class TestDestroyBean {public void test() {System.out.println(测试一下销毁方法);}PreDestroypublic void close() throws Exception {System.out.println(TestDestroyBean------自定义的Bean销毁方法);}
}2.3 其他方式手动指定销毁方法名字
当然还有其他方式如
bean destroy-methodxxx或者
Bean(destroyMethod xxx)又或者就是在beanDefinition里面直接指定销毁方法
Component
public class MyBeanPostProcessor implements MergedBeanDefinitionPostProcessor {Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class? beanType, String beanName) {if (beanName.equals(user)) {beanDefinition.setInitMethodName(myInit);beanDefinition.setDestroyMethodName(xxxx);}}
}
上面说的这三种方式有一个比较特殊的地方因为是手动指定的所以可以设置一个比较特殊的值(inferred)。 如果设置了销毁方法名字为这个并且Bean没有实现DisposableBean则在销毁的过程中会检索bean下面有没有close或者shutdown方法。有则自动绑定为【用户自定义销毁方法】。
三、注册销毁Bean过程及方法详解
本次销毁过程总过涉及了【3个核心类6个核心方法】
3.1 AbstractBeanFactory#requiresDestruction需要销毁吗 方法调用链从入口registerDisposableBeanIfNecessary()调用进来 全路径org.springframework.beans.factory.support.AbstractBeanFactory#requiresDestruction 方法注释将给定bean添加到此工厂中的一次性bean列表中注册其DisposableBean接口和/或给定的destroy方法以便在工厂关闭时调用(如果适用)。只适用于单例。 源码如下
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {return (bean.getClass() ! NullBean.class (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessorCache().destructionAware))));
}方法解读里面的关键源码其实就是分两个步骤。如下
是否有指定的销毁方法。DisposableBeanAdapter.hasDestroyMethod(bean, mbd)是否有DestructionAwareBeanPostProcessor能感知销毁的Bean后置处理器hasDestructionAwareBeanPostProcessors。有则遍历DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessorCache().destructionAware)
3.2 DisposableBeanAdapter.hasDestroyMethod是否有销毁方法 方法调用链由3.1中的requiresDestruction()调用过来 全路径org.springframework.beans.factory.support.DisposableBeanAdapter#hasDestroyMethod 方法注释检查给定bean是否有任何要调用的销毁方法。 源码如下
public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {return (bean instanceof DisposableBean || inferDestroyMethodIfNecessary(bean, beanDefinition) ! null);
}而里面的内容其实也很简单步骤如下
当前Bean是否实现了DisposableBean接口没有则调用inferDestroyMethodIfNecessary推断销毁方法后面讲
3.3 DisposableBeanAdapter#inferDestroyMethodIfNecessary推断销毁方法 方法调用链由3.2中的hasDestroyMethod()调用过来 全路径org.springframework.beans.factory.support.DisposableBeanAdapter#inferDestroyMethodIfNecessary 方法注释 如果给定beanDefinition的destroyMethodName属性的当前值是AbstractBeanDefinition。然后尝试推断一个销毁方法。候选方法目前仅限于名为“close”或“shutdown”的公共无参数方法(无论是在本地声明还是继承)。如果没有找到这样的方法则将给定BeanDefinition的“destroyMethodName”更新为null否则将设置为推断方法的名称。该常量作为Bean#destroyMethod属性的默认值该常量的值也可以在XML中或属性中使用。还处理java.io.Closeable和AutoCloseable接口并在实现bean时反射地调用“close”方法。 源码如下 Nullableprivate static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {String destroyMethodName beanDefinition.resolvedDestroyMethodName;if (destroyMethodName null) {destroyMethodName beanDefinition.getDestroyMethodName();boolean autoCloseable (bean instanceof AutoCloseable);if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||(destroyMethodName null autoCloseable)) {// 当销毁方法名字等于(inferred)且bean不是DisposableBean实现类destroyMethodName null;if (!(bean instanceof DisposableBean)) {if (autoCloseable) {destroyMethodName CLOSE_METHOD_NAME;}else {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);}方法解读没啥好解读的了直接重复贴一边注释就好了。尝试推断一个销毁方法。候选方法目前仅限于名为“close”或“shutdown”的公共无参数方法(无论是在本地声明还是继承)。如果没有找到这样的方法则将给定BeanDefinition的“destroyMethodName”更新为null否则将设置为推断方法的名称。该常量作为Bean#destroyMethod属性的默认值该常量的值也可以在XML中bean destroy-method“”或属性中使用。还处理java.io.Closeable和AutoCloseable接口并在实现bean时反射地调用“close”方法。
3.4 AbstractBeanFactory#hasDestructionAwareBeanPostProcessors是否有感知销毁Bean后置处理器 方法调用链由3.1中的requiresDestruction()调用过来 全路径org.springframework.beans.factory.support.AbstractBeanFactory#hasDestructionAwareBeanPostProcessors 方法注释返回该工厂是否持有一个DestructionAwareBeanPostProcessor该DestructionAwareBeanPostProcessor将在关闭时应用于单例bean。 源码如下 protected boolean hasDestructionAwareBeanPostProcessors() {return !getBeanPostProcessorCache().destructionAware.isEmpty();}3.5 DisposableBeanAdapter.hasApplicableProcessors是否有应用于当前Bean的销毁感知Bean后置处理器 方法调用链由3.1中的requiresDestruction()调用过来 全路径org.springframework.beans.factory.support.DisposableBeanAdapter#hasApplicableProcessors 方法注释检查给定bean是否有应用于它的销毁感知后处理器。 源码如下 public static boolean hasApplicableProcessors(Object bean, ListDestructionAwareBeanPostProcessor postProcessors) {if (!CollectionUtils.isEmpty(postProcessors)) {for (DestructionAwareBeanPostProcessor processor : postProcessors) {if (processor.requiresDestruction(bean)) {return true;}}}return false;}经典的BeanPostProcessor处理了不说了
3.6 DefaultSingletonBeanRegistry#registerDisposableBean注册需要销毁的bean 方法调用链从入口registerDisposableBeanIfNecessary()调用进来 全路径org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#registerDisposableBean 方法注释将给定的bean添加到此注册中心的销毁bean列表中。 源码如下
private final MapString, Object disposableBeans new LinkedHashMap();public void registerDisposableBean(String beanName, DisposableBean bean) {synchronized (this.disposableBeans) {this.disposableBeans.put(beanName, bean);}
}方法解读所谓的注册其实就是将当前bean及一些信息添加到一个缓存map中。等到需要用到的时候直接遍历map就好
3.7 注册销毁Bean过程总结
整体来说分为2个步骤
是单例bean判断是否需要销毁。判断步骤如下不同的Spring版本细节不一样但是整体是一致的 当前Bean是否实现了DisposableBean接口是则直接返回true否则进行【推断销毁方法】流程推断销毁方法 BeanDefinition中是否指定了destroyMethod且destroyMethod(inferred)。如果是则寻找当前bean下是否有close方法或者shutdown方法是则直接返回销毁方法名称或者当前Bean是否实现了AutoCloseable接口是则直接返回销毁方法名称 如果【推断销毁方法】也没有结果则调用【感知销毁Bean后置处理器】DestructionAwareBeanPostProcessor.requiresDestruction(bean)进行判断 ApplicationListenerDetector中直接使得如果当前bean是ApplicationListener子类需要销毁InitDestroyAnnotationBeanPostProcessor中使得拥有PreDestroy注解了的方法就是需要销毁 如果需要销毁则适配成DisposableBeanAdapter对象并存入disposableBeans中一个LinkedHashMap
四、注册销毁Bean逻辑流程图 五、概念回顾
这里用到的一个比较重要的后置处理器是InitDestroyAnnotationBeanPostProcessor它的定义如下 /***通用场景术语库beanpostprocessor实现调用带注释的init和destroy方法。允许一个注释替代Spring的org.springframework.beans.factory.InitializingBean和org.springframework.beans.factory.DisposableBean回调接口。这个后处理器检查的实际注释类型可以通过“initAnnotationType”和“destroyAnnotationType”属性来配置。可以使用任何自定义注释因为没有必需的注释属性。Init和destroy注释可以应用于任何可见性的方法:public、package-protected、protected或private。可以注释多个这样的方法但建议分别只注释一个init方法和destroy方法。Spring的org.springframework.context.annotation.CommonAnnotationBeanPostProcessor支持JSR-250开箱即用的javax.annotation.PostConstruct和javax.annotation.PreDestroy注释就像init annotation和destroy annotation一样。此外它还支持javax.annotation.Resource注释用于注释驱动的命名bean注入。自:2.5参见:setInitAnnotationType, setDestroyAnnotationType作者:Juergen hoel以上翻译结果来自有道神经网络翻译YNMT· 通用场景逐句对照*/public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
}学习总结
学习了Bean销毁过程学习了注册销毁Bean的逻辑学习了如何自定义Bean销毁逻辑