• 【spring源码系列】之【Bean的销毁】


     



    以“冬奥之光,多彩冰灯”为主题的第四十一届全国专业冰雕比赛在冰城哈尔滨市进入第二天,60名冰雕高手在哈尔滨冰灯艺术游园会园区展开激烈的竞技比拼。
    冰雕艺术

    1. 概述

    Bean的销毁是Bean的生命周期中最后一步,比如在Tomcat等容器关闭的时候会调用Bean的销毁方法,下面逐步分析。

    2. 源码分析

    在bean创建完成后,就会对这个bean注册一个销毁的Adapter对象,

    	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    			throws BeanCreationException {
    
    		......
    
    		if (instanceWrapper == null) {
    			//创建对象实例
    			instanceWrapper = createBeanInstance(beanName, mbd, args);
    		}
    		Object bean = instanceWrapper.getWrappedInstance();
    		Class<?> beanType = instanceWrapper.getWrappedClass();
    		if (beanType != NullBean.class) {
    			mbd.resolvedTargetType = beanType;
    		}
    
    		......
    
    		try {
    			// 属性赋值
    			populateBean(beanName, mbd, instanceWrapper);
    			// 初始化bean
    			exposedObject = initializeBean(beanName, exposedObject, mbd);
    		}
    		catch (Throwable ex) {
    			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
    				throw (BeanCreationException) ex;
    			}
    			else {
    				throw new BeanCreationException(
    						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    			}
    		}
    
    		......
    
    		// Register bean as disposable.
    		try {
    			// 注册销毁的bean
    			registerDisposableBeanIfNecessary(beanName, bean, mbd);
    		}
    		catch (BeanDefinitionValidationException ex) {
    			throw new BeanCreationException(
    					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    		}
    
    		return exposedObject;
    	}
    

    registerDisposableBeanIfNecessary方法中disposableBeans集合负责收集需要销毁的bean

    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
    		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
    		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.
    				// 注册销毁bean的DisposableBeanAdapter对象
    				registerDisposableBean(beanName,
    						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
    			}
                    ......
    
    
    public void registerDisposableBean(String beanName, DisposableBean bean) {
    		synchronized (this.disposableBeans) {
    			this.disposableBeans.put(beanName, bean);
    		}
    	}
    

    DisposableBeanAdapter 对象就是负责 bean 销毁的类,这个类中收集 bean是否实现了 DisposableBean 接口

    class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable 
    

    是否配置 destroy-method 属性,过滤了 DestructionAwareBeanPostProcessor 类型的接口,如下图所示:

    public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
    			List<BeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {
    
    		......
    
    		this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
    	}
    
    private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> processors, Object bean) {
    		List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
    		if (!CollectionUtils.isEmpty(processors)) {
    			filteredPostProcessors = new ArrayList<>(processors.size());
    			for (BeanPostProcessor processor : processors) {
    				if (processor instanceof DestructionAwareBeanPostProcessor) {
    					DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
    					if (dabpp.requiresDestruction(bean)) {
    						filteredPostProcessors.add(dabpp);
    					}
    				}
    			}
    		}
    		return filteredPostProcessors;
    

    然后 bean 是在什么时候被销毁呢,在 tomcat 关闭的时候就会调用到 servlet 中的销毁方法,具体是通过类ContextLoaderListener.java 中的contextDestroyed 方法,通过 closeWebApplicationContext 方法一直往下找此为 servlet 规范的使用,一路往下调用。








    最终会进入DisposableBeanAdapter类中的destroy,方法该方法就会根据前面的收集进行调用。

    public void destroy() {
    		// 处理@PreDestroy注解的beanpostProcessor实现类: InitDestroyAnnotationBeanPostProcessor
    		if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
    			for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
    				processor.postProcessBeforeDestruction(this.bean, this.beanName);
    			}
    		}
    		// 处理实现DisposableBean接口的bean的销毁
    		if (this.invokeDisposableBean) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
    			}
    			try {
    				if (System.getSecurityManager() != null) {
    					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
    						((DisposableBean) this.bean).destroy();
    						return null;
    					}, this.acc);
    				}
    				else {
    					((DisposableBean) this.bean).destroy();
    				}
    			}
    			catch (Throwable ex) {
    				String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
    				if (logger.isDebugEnabled()) {
    					logger.warn(msg, ex);
    				}
    				else {
    					logger.warn(msg + ": " + ex);
    				}
    			}
    		}
    
    		// 处理在配置文件中的bean配置了destroy-method的bean的销毁
    		if (this.destroyMethod != null) {
    			invokeCustomDestroyMethod(this.destroyMethod);
    		}
    		else if (this.destroyMethodName != null) {
    			Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
    			if (methodToInvoke != null) {
    				invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
    			}
    		}
    	}
    

    销毁bean的顺序是如下:
    1)判断是否需要处理@PreDestroy注解的bean,如果需要,则通过beanpostProcessor实现类 InitDestroyAnnotationBeanPostProcessor处理;
    2)判断是否需要处理实现DisposableBean接口的bean的销毁;
    3)判断是否需要处理配置文件中的bean配置了destroy-methodbean的销毁。

    3. 案例演示

    定义Bean,同时加入销毁对应的三种方法;

    /**
     * @Author: wzj
     * @Date: 2021/7/2 11:32
     * @Desc:
     */
    public class Wzj implements DisposableBean {
        
        @PreDestroy
        public void close() {
            System.out.println("通过 @PreDestroy:销毁实例wzj");
        }
    
        public void destroyMethod() {
            System.out.println("通过配置文件配置destroy-method:销毁实例wzj");
        }
    
        @Override
        public void destroy() {
            System.out.println("通过DisposableBean接口:销毁实例wzj");
        }
    

    配置文件如下:

    	<bean id="wzj"  class="com.wzj.bean.Wzj" factory-method="factoryMethod" destroy-method="destroyMethod"/>
    

    测试类:

    /**
     * @Author: wzj
     * @Date: 2021/3/30 15:08
     * @Desc: 测试类
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring.xml"})
    public class TestSpring {
    
        @Autowired
        private ApplicationContext applicationContext;
    
        @Test
        public void testDestroy() {
            ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
            Wzj wzj = (Wzj)applicationContext.getBean("wzj");
            applicationContext.getBeanFactory().destroyBean("wzj");
      
        }
    

    结果:

    有人可能会问,为何Bean可以多次销毁,其实Bean的销毁并不是真正意义上的销毁Bean,而是在销毁前执行销毁方法,可能包含关闭数据库连接、关闭网络请求等逻辑操作,而后真正的销毁是由Spring容器执行关闭,其内部Bean也就自然而然消失了,Bean销毁是发生在Spring容器关闭过程中的。


    __EOF__

    本文作者小猪爸爸
    本文链接https://www.cnblogs.com/father-of-little-pig/p/15962244.html
    关于博主:不要为了技术而技术,总结分享技术,感恩点滴生活!
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
  • 相关阅读:
    计算机毕业设计ssm基于ssm的牧场管理系统6ui1j系统+程序+源码+lw+远程部署
    每日一题之原子的数量
    JMeter笔记9 | JMeter参数化
    Java当中聊一聊String吧
    【Web前端入门】HTML+CSS 万字总结——带你深入学习掌握
    Java扩展Nginx之四:远程调试
    iOS Error Domain=PHPhotosErrorDomain Code=3300
    try catch 中的finally什么时候运行
    【英雄哥七月集训】第 04天:贪心
    Android S(31) PMS 服务启动原理
  • 原文地址:https://www.cnblogs.com/father-of-little-pig/p/15962244.html