• 【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");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    源码:

    	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))));
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码调试:
    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");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    源码:

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

    源码调试:
    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");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    @ComponentScan("com.cms")
    public class AppConfig {
    
    	@Bean(destroyMethod = "destroy")
    	public OrderService createOrderService () {
    		return new OrderService();
    	}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

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

    代码示例:

    public class OrderService {
    
      // 必须是close方法
    	public void close () {
    		System.out.println("OrderService#destroy");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    @ComponentScan("com.cms")
    public class AppConfig {
    
    	@Bean(destroyMethod = "(inferred)")
    	public OrderService createOrderService () {
    		return new OrderService();
    	}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    源码:

    	@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);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    手动指定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-后置处理器销毁");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    或者

    @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销毁");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    二、Bean销毁-源码分析

    声明关键点

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

    源代码

    注册

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

    // 只做一件事情:注册实现了'销毁'方法的bean。
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
    
    • 1
    • 2
    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));
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    销毁

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

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

    在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接口。
  • 相关阅读:
    MCM箱模型建模方法及大气O3来源解析
    计算机网络---概述
    如何理解my_map.yaml中origin的含义
    《Netty二》
    开仓风险计算器.xlsx(可计算:名义价值、最大资金亏损、开仓所需保证金、开仓资金杠杆、最小逐仓保证金、U本位需开张数、币本位需开张数)
    Java程序设计2023-第六次上机练习
    phpStorm Xdebug调试 加FireFox浏览器
    Vue.js vs React:哪一个更适合你的项目?
    汇川AM400高速计数器应用编程(配置+CODESYS源代码)
    java毕业设计疫情防控信息管理系统Mybatis+系统+数据库+调试部署
  • 原文地址:https://blog.csdn.net/qq_43783527/article/details/128172577