0


【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注解

代码示例:

@ComponentpublicclassUserService{@AutowiredprivateOrderService orderService;publicvoidtest(){System.out.println(orderService);}@PreDestroypublicvoid myDestroyUserServiceMethod (){System.out.println("UserService#myDestroyUserServiceMethod");}}

源码:

protectedbooleanrequiresDestruction(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接口

代码示例:

@ComponentpublicclassUserServiceimplementsDisposableBean{@AutowiredprivateOrderService orderService;publicvoidtest(){System.out.println(orderService);}@Overridepublicvoid destroy (){System.out.println("UserService#destroy");}}

源码:

publicstaticbooleanhasDestroyMethod(Object bean,RootBeanDefinition beanDefinition){// 是否实现了这两个接口中的一个if(bean instanceofDisposableBean|| bean instanceofAutoCloseable){returntrue;}// 判断BeanDefinition是否指定了销毁方法returninferDestroyMethodIfNecessary(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;

publicclassOrderService{publicvoid destroy (){System.out.println("OrderService#destroy");}}
@ComponentScan("com.cms")publicclassAppConfig{@Bean(destroyMethod ="destroy")publicOrderService createOrderService (){returnnewOrderService();}}

在这里插入图片描述

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

代码示例:

publicclassOrderService{// 必须是close方法publicvoid close (){System.out.println("OrderService#destroy");}}
@ComponentScan("com.cms")publicclassAppConfig{@Bean(destroyMethod ="(inferred)")publicOrderService createOrderService (){returnnewOrderService();}}

源码:

@NullableprivatestaticStringinferDestroyMethodIfNecessary(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 instanceofAutoCloseable)){// Only perform destroy method inference or Closeable detection// in case of the bean not explicitly implementing DisposableBean
                destroyMethodName =null;if(!(bean instanceofDisposableBean)){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后置处理器设置销毁方法)

@ComponentpublicclassMyMergeBdfPostProcesserimplementsMergedBeanDefinitionPostProcessor{@OverridepublicvoidpostProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,Class<?> beanType,String beanName){if(beanName.equals("myDisposableBean3")){
            beanDefinition.setDestroyMethodName("a");}}}@ComponentpublicclassMyDisposableBean3{publicvoida(){System.out.println("MyMergeBdfPostProcesser-后置处理器销毁");}}

或者

@ComponentpublicclassMyMergeBdfPostProcesser2implementsMergedBeanDefinitionPostProcessor{@OverridepublicvoidpostProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,Class<?> beanType,String beanName){if(beanName.equals("myDisposableBean4")){
            beanDefinition.setDestroyMethodName("(inferred)");}}}@ComponentpublicclassMyDisposableBean4{//    public void close()  {//        System.out.println("close销毁");//    }publicvoidshutdown(){System.out.println("shutdown销毁");}}

二、Bean销毁-源码分析

声明关键点

1、

原型bean即使定义了销毁方法,也不会执行销毁方法

。因为我们的原型bean根本没有存,更不要说去调用原型bean的销毁方法了。

源代码

注册

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

// 只做一件事情:注册实现了'销毁'方法的bean。registerDisposableBeanIfNecessary(beanName, bean, mbd);
protectedvoidregisterDisposableBeanIfNecessary(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,newDisposableBeanAdapter(
                        bean, beanName, mbd,getBeanPostProcessorCache().destructionAware, acc));}else{// A bean with a custom scope...Scope scope =this.scopes.get(mbd.getScope());if(scope ==null){thrownewIllegalStateException("No Scope registered for scope name '"+ mbd.getScope()+"'");}
                scope.registerDestructionCallback(beanName,newDisposableBeanAdapter(
                        bean, beanName, mbd,getBeanPostProcessorCache().destructionAware, acc));}}}

销毁

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

protectedvoiddestroyBeans(){// 只对单例bean存储销毁方法,原型bean不会存储(因为原型bean每次调用都会创建新bean对象)// DefaultListableBeanFactorygetBeanFactory().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接口。
标签: spring java

本文转载自: https://blog.csdn.net/qq_43783527/article/details/128172577
版权归原作者 @来杯咖啡 所有, 如有侵权,请联系我们删除。

“【Spring源码系列】Bean生命周期-Bean销毁”的评论:

还没有评论