【Spring源码系列】Bean生命周期-Bean销毁

前言

Spring给我们提供了一种当bean销毁时调用某个方法的方式。那么,Spring底层到底是如何实现的呢?接下来,我们将从源码+案例的方式来解析:spring如何实现当bean销毁时调用某个方法的。

一、Bean销毁介绍

bean销毁的时机

spring容器关闭的时候(调用close())方法的时候,所有的单例bean都会被销毁,并且对于实现destroy方法的bean,也会在此刻执行各自自定义的销毁逻辑

提示:
是spring容器关闭的时候调用bean销毁逻辑,不是垃圾回收、程序意外终止、程序正常终止…的时候。

spring注册DestroyBean时机

1、注册DisposableBeans。在‘初始化后’会对BeanDefinition进行判断,判断该BeanDefinition是否具备destroy方法,如果具备则把BeanDefinition注册到DisposableBeans。具体如何判断的,我们下面会讲;
在这里插入图片描述
2、执行destroy方法。当调用close方法的时候,会遍历DisposableBeans执行每一个销毁方法

定义bean销毁方式以及源码调试

此处不仅仅写了代码示例,也把源码贴出来进行验证。

使用@PreDestroy注解

代码示例:

@Component
public class UserService {

	@Autowired
	private OrderService orderService;

	public void test(){
		System.out.println(orderService);
	}

	@PreDestroy
	public void myDestroyUserServiceMethod () {
		System.out.println("UserService#myDestroyUserServiceMethod");
	}
}

源码:

	protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
		// hasDestroyMethod: 实现了DisposableBean或者AutoCloseable接口	,或者创建bean的时候手动指定了销毁方法( 比如@Bean(destroyMethod = "destory")、xml中的bean标签中指定destroyMethod)
		return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
				// @PreDestroy注解
				(hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
						bean, getBeanPostProcessorCache().destructionAware))));
	}

代码调试:
CommonAnnotationBeanPostProcessor:
在这里插入图片描述UserService#myDestroyUserServiceMethod销毁方法在Spring容器启动的时候就已经被记录在CommonAnnotationBeanPostProcessor中了,当调用org.springframework.beans.factory.support.AbstractBeanFactory#requiresDestruction判断该bean是否定义销毁逻辑的时候返回的是true:
在这里插入图片描述

实现DisposableBean或者AutoCloseable接口

代码示例:

@Component
public class UserService implements DisposableBean {

	@Autowired
	private OrderService orderService;

	public void test(){
		System.out.println(orderService);
	}

	@Override
	public void destroy () {
		System.out.println("UserService#destroy");
	}
}

源码:

	public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
		// 是否实现了这两个接口中的一个
		if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
			return true;
		}
		// 判断BeanDefinition是否指定了销毁方法
		return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
	}

源码调试:
UserService 实现了 DisposableBean 接口,所以DisposableBeanAdapter.hasDestroyMethod(bean, mbd)返回true,且可以发现CommonAnnotationBeanPostProcessor#lifecycleMetadataCache集合中的UserService.class并没指定destroyMethods:
在这里插入图片描述

手动指定destroy方法(@Bean、XML)

手动指定dstroy方法有两种方式:
1、@Bean注解方式指定destroyMethod;
2、XML文件中< bean >标签里面指定destry-method;

public class OrderService {

	public void destroy () {
		System.out.println("OrderService#destroy");
	}
}
@ComponentScan("com.cms")
public class AppConfig {

	@Bean(destroyMethod = "destroy")
	public OrderService createOrderService () {
		return new OrderService();
	}
	
}

在这里插入图片描述

手动指定destroy方法((inferred))

代码示例:

public class OrderService {

  // 必须是close方法
	public void close () {
		System.out.println("OrderService#destroy");
	}
}
@ComponentScan("com.cms")
public class AppConfig {

	@Bean(destroyMethod = "(inferred)")
	public OrderService createOrderService () {
		return new OrderService();
	}
	
}

源码:

	@Nullable
	private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
		// 判断BeanDefinition是否指定了销毁方法(比如创建bean的时候(@Bean、xml),手动指定destroyMethod)
		String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
		// 下面这种定义销毁的方式,不常用。流程:先定义销毁方法-(inferred) ,然后调用close方法。
		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);
	}

手动指定destroy方法(MergedBeanDefinitionPostProcessor后置处理器设置销毁方法)

@Component
public class MyMergeBdfPostProcesser implements MergedBeanDefinitionPostProcessor {
	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		if (beanName.equals("myDisposableBean3")){
			beanDefinition.setDestroyMethodName("a");
		}
	}
}
 
 
@Component
public class MyDisposableBean3 {
 
	public void a()  {
		System.out.println("MyMergeBdfPostProcesser-后置处理器销毁");
	}
}

或者

@Component
public class MyMergeBdfPostProcesser2 implements MergedBeanDefinitionPostProcessor {
	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		if (beanName.equals("myDisposableBean4")){
			beanDefinition.setDestroyMethodName("(inferred)");
		}
	}
}
 
 
 
@Component
public class MyDisposableBean4 {
 
//	public void close()  {
//		System.out.println("close销毁");
//	}
 
 
	public void shutdown()  {
		System.out.println("shutdown销毁");
	}
}

二、Bean销毁-源码分析

声明关键点

1、原型bean即使定义了销毁方法,也不会执行销毁方法。因为我们的原型bean根本没有存,更不要说去调用原型bean的销毁方法了。

源代码

注册

源码位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

// 只做一件事情:注册实现了'销毁'方法的bean。
registerDisposableBeanIfNecessary(beanName, bean, mbd);
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
		// if(不是'多例'bean && 有销毁方法)
		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));
			}
		}
	}

销毁

源码位置:org.springframework.context.support.AbstractApplicationContext#close

	protected void destroyBeans() {
		// 只对单例bean存储销毁方法,原型bean不会存储(因为原型bean每次调用都会创建新bean对象)
		// DefaultListableBeanFactory
		getBeanFactory().destroySingletons();
	}

在Spring容器关闭过程时:

  1. 首先发布ContextClosedEvent事件
  2. 调用lifecycleProcessor的onCloese()方法
  3. 销毁单例Bean
    a. 遍历disposableBeans
    ⅰ. 把每个disposableBean从单例池中移除
    ⅱ. 调用disposableBean的destroy()
    ⅲ. 如果这个disposableBean还被其他Bean依赖了,那么也得销毁其他Bean
    ⅳ. 如果这个disposableBean还包含了inner beans,将这些Bean从单例池中移除掉 (inner bean参考https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-inner-beans)
    b. 清空manualSingletonNames,是一个Set,存的是用户手动注册的单例Bean的beanName
    c. 清空allBeanNamesByType,是一个Map,key是bean类型,value是该类型所有的beanName数组
    d. 清空singletonBeanNamesByType,和allBeanNamesByType类似,只不过只存了单例Bean
    这里涉及到一个设计模式:适配器模式
    在销毁时,Spring会找出实现了DisposableBean接口的Bean。
    但是我们在定义一个Bean时,如果这个Bean实现了DisposableBean接口,或者实现了AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么这个Bean都属于“DisposableBean”,这些Bean在容器关闭时都要调用相应的销毁方法。
    所以,这里就需要进行适配,将实现了DisposableBean接口、或者AutoCloseable接口等适配成实现了DisposableBean接口,所以就用到了DisposableBeanAdapter。
    会把实现了AutoCloseable接口的类封装成DisposableBeanAdapter,而DisposableBeanAdapter实现了DisposableBean接口。
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring框架中,Bean的生命周期可以分为以下几个阶段: 1. 实例化(Instantiation):容器创建Bean的实例。 2. 属性赋值(Populate):容器将Bean的属性值设置到对应的属性中。 3. 初始化(Initialization):容器调用Bean的初始化方法。 4. 使用(In Use):Bean被容器使用。 5. 销毁(Destruction):容器销毁Bean的实例。 下面我们来详细介绍一下这些阶段。 1. 实例化 Bean的实例化可以通过两种方式实现: (1)使用构造函数创建Bean的实例。 (2)使用工厂方法创建Bean的实例。 无论使用哪种方式,一旦Bean实例化完成,Spring容器就会拥有该Bean的实例对象。 2. 属性赋值 属性赋值是指将Bean的属性值设置到对应的属性中。Spring框架提供了三种方式实现属性赋值: (1)通过构造函数注入。 (2)通过Setter方法注入。 (3)通过自动装配注入。 其中,自动装配注入分为byName、byType、constructor、autodetect四种方式。 3. 初始化 初始化是指在Bean实例化并完成属性赋值后,Spring容器会调用Bean的初始化方法进行一些额外的设置或操作。初始化方法包括两种: (1)实现InitializingBean接口的afterPropertiesSet()方法。 (2)在Bean配置文件中使用init-method属性指定初始化方法。 4. 使用 使用阶段是指Spring容器将Bean实例注入到需要使用该实例的地方,比如注入到其他Bean中。 5. 销毁 销毁阶段是指Spring容器在销毁Bean实例前会调用Bean的销毁方法进行一些清理工作。销毁方法包括两种: (1)实现DisposableBean接口的destroy()方法。 (2)在Bean配置文件中使用destroy-method属性指定销毁方法。 以上就是SpringBean的生命周期,通过了解Bean的生命周期,我们可以更好地理解Spring的运行机制,并且可以更好地使用Spring框架进行开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@来杯咖啡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值