Bean使用阶段,调用getBean()得到bean之后,根据需要,自行使用。
1 销毁Bean的几种方式
- 调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#destroyBean
- 调用org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons
- 调用ApplicationContext中的close方法,实际会调用起BeanFactory的destroySingletons方法
第一种为销毁单个bean,后两种为销毁容器中所有的单例beans。我们下面主要讲解第一种方式,后面等到讲解容器的时候在详细介绍。
2 Bean销毁逻辑
- 轮询beanPostProcessors列表,如果是DestructionAwareBeanPostProcessor这种类型的,会调用其内部的postProcessBeforeDestruction方法
- 如果bean实现了org.springframework.beans.factory.DisposableBean接口,会调用这个接口中的destroy方法
- 如果bean实现了java.lang.AutoCloseable接口,调用该接口中的close()方法,这个下面不详细讲解。
- 调用bean自定义的销毁方法
追踪下AbstractAutowireCapableBeanFactory#destroyBean方法,代码如下:
@Override
public void destroyBean(Object existingBean) {
new DisposableBeanAdapter(existingBean, getBeanPostProcessorCache().destructionAware).destroy();
}
会继续调用DisposableBeanAdapter的destroy方法,代码如下:
@Override
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
if (this.invokeDisposableBean) {
// 省略日志记录
try {
((DisposableBean) this.bean).destroy();
}
// 省略异常处理
}
if (this.invokeAutoCloseable) {
// 省略日志记录
try {
((AutoCloseable) this.bean).close();
}
// 省略异常处理
}
else if (this.destroyMethods != null) {
for (Method destroyMethod : this.destroyMethods) {
invokeCustomDestroyMethod(destroyMethod);
}
}
else if (this.destroyMethodNames != null) {
for (String destroyMethodName: this.destroyMethodNames) {
Method destroyMethod = determineDestroyMethod(destroyMethodName);
if (destroyMethod != null) {
invokeCustomDestroyMethod(
ClassUtils.getInterfaceMethodIfPossible(destroyMethod, this.bean.getClass()));
}
}
}
}
3 DestructionAwareBeanPostProcessor后置处理器
package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
/**
* 销毁之前执行
*/
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
/**
* 是否要执行销毁
*/
default boolean requiresDestruction(Object bean) {
return true;
}
}
3.1 CommonAnnotationBeanPostProcessor
其中这个接口有个重要的实现类
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
这个类中并没有postProcessBeforeDestruction方法,即它直接继承自起父类InitDestroyAnnotationBeanPostProcessor,代码如下:
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeDestroyMethods(bean, beanName);
}
// 省略。。。
}
public void invokeDestroyMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedDestroyMethods = this.checkedDestroyMethods;
Collection<LifecycleElement> destroyMethodsToUse =
(checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods);
if (!destroyMethodsToUse.isEmpty()) {
for (LifecycleElement element : destroyMethodsToUse) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking destroy method on bean '" + beanName + "': " + element.getMethod());
}
element.invoke(target);
}
}
}
那么在detroMethods中有哪些销毁方法呢?我们看下上面findLifecycleMetadata方法,代码如下;
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;
}
- 判断lifecycleMetadataCache缓存为空
- 为空,执行buildLifecycleMetadata方法
- 不为空,直接缓存获取
我们看下缓存为空的情况,即执行buildLifecycleMetadata方法,
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 -> {
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);
}
}
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的初始化方法和销毁方法:
-
遍历目标bean Class的方法,判断方法上注解是否是initAnnotationType类型,如果是加入初始化方法集合;如果方法注解是destroyAnnotationType类型,加入销毁方法集合。
-
initAnnotationType和destroyAnnotationType类型,是在CommonAnnotationBeanPostProcessor类的构造方法里面设置的
public CommonAnnotationBeanPostProcessor() { setOrder(Ordered.LOWEST_PRECEDENCE - 3); setInitAnnotationType(PostConstruct.class); setDestroyAnnotationType(PreDestroy.class); // java.naming module present on JDK 9+? if (jndiPresent) { this.jndiFactory = new SimpleJndiBeanFactory(); } } -
即destroyAnnotationType类型就是判断方法注解是否是@PreDestroy
CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction方法中会调用bean中所有标注了@PreDestroy的方法
4 @PreDestroy注解
@PreDestroy注解主要用于在对象销毁前执行一些清理工作,比如释放资源或者关闭连接。
下面来做个测试,测试代码如下:
package com.gaogzhen.myspring.bean;
import jakarta.annotation.PreDestroy;
/**
* 测试@PreDestory
* @author gaogzhen
*/
public class DestroyBean {
public DestroyBean() {
System.out.println("creat======");
}
@PreDestroy
public void testPreDestroy() {
System.out.println("===preDestroy===");
}
}
@Test
public void testPreDestroy() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 自定义DestructionAwareBeanPostProcessor
factory.addBeanPostProcessor((DestructionAwareBeanPostProcessor) (bean, beanName) -> System.out.println("准备销毁bean:" + beanName));
// 默认CommonAnnotationBeanPostProcessor
factory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
// 容器注入BeanDefinition
factory.registerBeanDefinition("destroyBean", BeanDefinitionBuilder.genericBeanDefinition(DestroyBean.class).getBeanDefinition());
// 触发所有单例bean初始化
factory.preInstantiateSingletons();
// 销毁指定bean
factory.destroySingleton("destroyBean");
}
测试结果:
creat======
准备销毁bean:destroyBean
===preDestroy===
5 DisposableBean接口
public interface DisposableBean {
/**
* 在bean被销毁时被调用
*/
void destroy() throws Exception;
}
- 作用用于销毁前释放资源或者连接
这里不单独做测试,在下面#6一起测试下执行顺序。
6 自定义销毁方法
我们将通过AnnotationConfigApplicationContext来演示下,当bean被销毁时,@PreDestroy,DisposableBean以及自定义销毁方法的执行顺序。
示例代码如下6-1所示:
package com.gaogzhen.myspring.service;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.DisposableBean;
/**
* 测试销毁相关的方法执行顺序
* @author gaogzhen
*/
public class ServiceDestroy implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean接口方法执行");
}
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy注解方法执行");
}
public void customDestroy() {
System.out.println("自定义销毁方法执行");
}
}
public class TestDestroy {
@Bean(destroyMethod = "customDestroy")
public ServiceDestroy serviceDestroy() {
return new ServiceDestroy();
}
@Test
public void testDestroyOrder() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(TestDestroy.class);
System.out.println("准备启动容器");
context.refresh();
System.out.println("容器启动完毕");
System.out.println("serviceDestroy: " + context.getBean(ServiceDestroy.class));
System.out.println("准备关闭容器");
context.close();
System.out.println("容器关闭");
}
}
测试结果:
准备启动容器
容器启动完毕
serviceDestroy: com.gaogzhen.myspring.service.ServiceDestroy@40e10ff8
准备关闭容器
@PreDestroy注解方法执行
DisposableBean接口方法执行
容器关闭
后记
如果小伙伴什么问题或者指教,欢迎交流。
❓QQ:806797785
⭐️源代码仓库地址:https://gitee.com/gaogzhen/spring6-study
参考:
[1]Spring系列之Bean生命周期详解[CP/OL]
1553

被折叠的 条评论
为什么被折叠?



