0108Bean销毁-Bean生命周期详解-spring

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]

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gaog2zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值