zipfile.zipfile需要close吗_Spring的destory回调你真的搞懂了吗?

d9942a5486d104ee9af6e91b367170b4.png

销毁回调

Spring的初始化回调你真的搞懂了吗?

接着前篇,有初始化对应着就有销毁。Spring提供了多种方式的销毁回调方法,这些方法在手动关闭容器的时候就会触发。

销毁回调方式:

  1. 后置处理器DestructionAwareBeanPostProcessor的postProcessBeforeDestruction()方法,此方式是对所有bean有效
  2. 在类方法上使用@PreDestroy注解
  3. 实现接口DisposableBean的destory()方法
  4. 自定义回调方法,@Bean(destroyMethod = "beanDestoryCallbackMethod")
  5. 实现AutoCloseable接口或者Closeable接口的bean(当且仅当此bean没有任何自定义销毁回调,也就是说此bean没有使用前面的2,3,4这三种方式)

仍然按照前篇的思路,先演示,再提疑问,再读源码。

演示案例

自定义一个实现前面四种方式中的后三种方式的bean,实现DisposableBean接口,在bean中使用@PreDestory注解。然后在注入容器的时候使用@Bean注解。

package com.ubuntuvim.spring.createbean;import org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;import org.springframework.context.support.AbstractApplicationContext;import javax.annotation.PreDestroy;import java.io.IOException;/** * 和InitCallbackBean是相互呼应的,有销毁回调对应着就有销毁的回调。 * 验证各种销毁回调方法的执行顺序: * 1. 执行销毁回调DestructionAwareBeanPostProcessor.postProcessBeforeDestruction()方法 * 2. 执行销毁回调@PreDestroy注解的回调方法twoDestroy() * 3. 执行销毁回调@PreDestroy注解的回调方法oneDestroy() * 4. 执行销毁回调DisposableBean.destory()方法 * 5. 执行销毁回调@Bean(destroyMethod = "beanDestoryCallbackMethod")的方法 * * 需要注意的是,这些销毁的回调方法需要手动调用容器的关闭方法才会触发。触发方法如下: * @see AbstractApplicationContext#close() * 最终会调用到这个类的方法处理上述回调接口。 * @see DisposableBeanAdapter#destroy() * * @Author: ubuntuvim * @Date: 2020/10/18 下午5:17 */public class DestoryCallbackBean implements DisposableBean, /*Closeable, */AutoCloseable {    // 实现DisposableBean接口的方法    @Override    public void destroy() throws Exception {        System.out.println("执行销毁回调DisposableBean.destory()方法");    }    // 自定义销毁方法:@Bean(destroyMethod = "beanDestoryCallbackMethod")    private void beanDestoryCallbackMethod() {        System.out.println("执行销毁回调@Bean(destroyMethod = "beanDestoryCallbackMethod")的方法");    }    // 如果有一个同名销毁方法会不会被读取使用??不会,因为@Bean只支持无参方法    private void beanDestoryCallbackMethod(Fruit apple) {        apple.eatable();        System.out.println("执行销毁回调@Bean(destroyMethod = "beanDestoryCallbackMethod")的方法");    }    /**     * 如果一个类中有两个方法都使用了@PreDestory注解会怎么执行?     * 都会执行,执行代码:     * @see DefaultSingletonBeanRegistry#destroySingletons()     * 但是如果DispoableBean的destory()方法也使用了@PreDestory注解则只会执行一次。     * 这个和初始化的InitializingBean.afterPropertiesSet()方法类似,只会执行一次。     */    @PreDestroy    public void twoDestroy() {        System.out.println("执行销毁回调@PreDestroy注解的回调方法twoDestroy()");    }    @PreDestroy    public void oneDestroy() {        System.out.println("执行销毁回调@PreDestroy注解的回调方法oneDestroy()");    }    /**     * 实现接口AutoCloseable的方法。     * bean没有实现任何销毁回调,也没有在@Bean中自定义任何销毁方法下,当容器执行close事件时此方法会被执行。     * 比如SimpleDestoryBean类的例子。     * @throws IOException     */    @Override    public void close() throws IOException {        System.out.println("执行销毁回调Closeable.close()方法");    }        public void shutdown() {        System.out.println("执行销毁回调shutdown()方法");    }}

还有一种默认的回调,就是实现AutoCloseable接口或者Closeable接口。

package com.ubuntuvim.spring.createbean;import org.springframework.stereotype.Component;import java.io.Closeable;/** * 当前bean既不实现DispoableBean接口,也没有自定义的销毁方法 * 但是有一个AutoCloseable.close()方法,验证容器关闭时是否会回调AutoCloseable.close()方法。 * 实现Closeable接口也是同样的效果。 * @Author: ubuntuvim * @Date: 2020/10/18 下午10:38 */@Componentpublic class SimpleDestoryBean implements Closeable {    @Override    public void close() {        System.out.println("既不实现DispoableBean接口,也没有自定义的销毁方法的情况下执行最后默认的AutoCloseable.close方法");    }}

再定义一个后置处理器,实现DestructionAwareBeanPostProcessor接口。

/** * 自定义销毁回调的后置处理器 * @Author: ubuntuvim * @Date: 2020/10/18 下午5:23 */@Componentpublic class MyDestructionAwareBeanPostProcessorImpl implements DestructionAwareBeanPostProcessor {    @Override    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {        if ("DestoryCallbackBean".equalsIgnoreCase(beanName))            System.out.println("执行销毁回调DestructionAwareBeanPostProcessor.postProcessBeforeDestruction()方法");    }    @Override    public boolean requiresDestruction(Object bean) {        // 返回true,表示需要执行销毁回调方法postProcessBeforeDestruction()        return true;    }}

最后,通过@Bean注入到容器中。

package com.ubuntuvim.spring.createbean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;/** * @Author: ubuntuvim * @Date: 2020/10/17 下午4:46 */@ComponentScan@Configurationpublic class Config {    @Bean(destroyMethod = "beanDestoryCallbackMethod")    public DestoryCallbackBean destoryCallbackBean() {        return new DestoryCallbackBean();    }}

运行案例;

package com.ubuntuvim.spring.createbean;import org.springframework.beans.factory.support.RootBeanDefinition;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.support.AbstractApplicationContext;/** * @Author: ubuntuvim * @Date: 2020/10/17 下午4:48 */public class CreateBeanTest {    public static void main(String[] args) {        AbstractApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);        // 执行各种销毁回调        applicationContext.close();    }}

applicationContext.close();这句代码非常关键,必须要手动关闭容器才会触发销毁回调的执行。你可以把这行代码注释掉在运行,注释掉之后不会打印如下的日志。即使是后置处理器接口也不会执行。

执行销毁回调DestructionAwareBeanPostProcessor.postProcessBeforeDestruction()方法执行销毁回调@PreDestroy注解的回调方法oneDestroy()执行销毁回调@PreDestroy注解的回调方法twoDestroy()执行销毁回调DisposableBean.destory()方法执行销毁回调@Bean(destroyMethod = "beanDestoryCallbackMethod")的方法既不实现DispoableBean接口,也没有自定义的销毁方法的情况下执行最后默认的AutoCloseable.close方法

Spring源码

接下来,我们从Spring源码入手,看看这些回调是在什么地方执行的。首先在main方法中的close方法上打个断点,然后用debug方式运行main方法。

进入到close()方法的逻辑里面。

@Overridepublic void close() {  synchronized (this.startupShutdownMonitor) {    doClose();    // If we registered a JVM shutdown hook, we don't need it anymore now:    // We've already explicitly closed the context.    if (this.shutdownHook != null) {      try {        Runtime.getRuntime().removeShutdownHook(this.shutdownHook);      }      catch (IllegalStateException ex) {        // ignore - VM is already shutting down      }    }  }}

按照Spring框架的尿性,不用想,具体处理逻辑肯定是在doClose()里面。

protected void doClose() {  // Check whether an actual close attempt is necessary...  if (this.active.get() && this.closed.compareAndSet(false, true)) {    if (logger.isDebugEnabled()) {      logger.debug("Closing " + this);    }    LiveBeansView.unregisterApplicationContext(this);    try {      // Publish shutdown event.      // 发布容器关闭事件,任何监听ContextClosedEvent事件的监听器都可以收到一条消息      publishEvent(new ContextClosedEvent(this));    }    catch (Throwable ex) {      logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);    }    // Stop all Lifecycle beans, to avoid delays during individual destruction.    if (this.lifecycleProcessor != null) {      try {        this.lifecycleProcessor.onClose();      }      catch (Throwable ex) {        logger.warn("Exception thrown from LifecycleProcessor on context close", ex);      }    }    // Destroy all cached singletons in the context's BeanFactory.    // 这个方法里面会执行自定义的销毁方法(@Bean),实现DisposableBean接口的方法,    // 以及InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestruction方法    destroyBeans();    // Close the state of this context itself.    // 设置容器上下文状态,    closeBeanFactory();    // Let subclasses do some final clean-up if they wish...    // 留给子类实现的自定义销毁逻辑    onClose();    // Reset local application listeners to pre-refresh state.    // 清理事件监听    if (this.earlyApplicationListeners != null) {      this.applicationListeners.clear();      this.applicationListeners.addAll(this.earlyApplicationListeners);    }    // Switch to inactive.    // 设置容器状态为关闭    this.active.set(false);  }}

这个方法做的事情很多,主要有:触发所有bean的销毁回调、发布关闭事件、执行bean的生命周期关闭方法、设置容器的状态为关闭、执行销毁的后置处理器。

本篇重点关注的是destroyBeans()方法。这个方法里面会执行自定义的销毁方法,@PreDestory注释的方法,后置处理器的postProcessBeforeDestruction()方法。

进入destoryBeans()方法后,发现这还不是最后的执行逻辑,这个方法又交给DefaultListableBeanFactory的destroySingletons()方法处理。

进入destorySingletons()方法后,发现还不是最好的执行逻辑,它的实现是调用父类的同名方法,继续进入它父类同名方法。DefaultSingletonBeanRegistry的destroySingletons()。

// DefaultSingletonBeanRegistry的destroySingletons()方法public void destroySingletons() {  if (logger.isTraceEnabled()) {    logger.trace("Destroying singletons in " + this);  }  synchronized (this.singletonObjects) {    this.singletonsCurrentlyInDestruction = true;  }  String[] disposableBeanNames;  synchronized (this.disposableBeans) {    disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());  }  // 遍历所有bean,逐个执行这些bean的销毁方法  for (int i = disposableBeanNames.length - 1; i >= 0; i--) {    destroySingleton(disposableBeanNames[i]);  }  this.containedBeanMap.clear();  this.dependentBeanMap.clear();  this.dependenciesForBeanMap.clear();  clearSingletonCache();}

最核心的逻辑在for循环里面,遍历所有可销毁的bean数组disposableBeanNames。

继续一步步进入调用逻辑,按照如下调用顺序就可以找到最后的执行逻辑:

DefaultSingletonBeanRegistry.destroySingletons() -> DefaultSingletonBeanRegistry.destroySingleton() -> DisposableBeanAdapter.destroy()

DisposableBeanAdapter.destory()才是最后的处理逻辑。不得不说这个调用层次实在是太深了!!

public void destroy() {  if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {    for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {      /**                 * 执行后置处理器的销毁回调方法                 * @PreDestroy注释的方法就是在这里执行的。默认实现有                 * @see InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestruction(Object, String)                 */      processor.postProcessBeforeDestruction(this.bean, this.beanName);    }  }  if (this.invokeDisposableBean) {    if (logger.isTraceEnabled()) {      logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");    }    // 执行DisposableBean接口的destory()方法。    try {      if (System.getSecurityManager() != null) {        AccessController.doPrivileged((PrivilegedExceptionAction) () -> {          ((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);      }    }  }  // 1. 执行自定义的销毁方法,比如下面自定义的销毁方法就是beanDestoryCallbackMethod()    //         @Bean(destroyMethod = "beanDestoryCallbackMethod")    // 2. 执行实现Closable接口的close()方法。  if (this.destroyMethod != null) {    invokeCustomDestroyMethod(this.destroyMethod);  }  else if (this.destroyMethodName != null) {    Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);    if (methodToInvoke != null) {      invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));    }  }}
  1. 首先遍历后置处理器的postProcessBeforeDestruction()方法,这个方法是对所有bean生效的。
  2. @PreDestory注解标注的方法也是通过后置处理器执行的。当遍历到InitDestroyAnnotationBeanPostProcessor这个后置处理器的时候,执行的原理和初始化回调是一样的,底层都是通过反射实现。
  3. 然后是执行单个bean实现的DisposableBean接口的destory()方法,
  4. 最后是执行在@Bean中自定义的销毁回调方法。
  5. 执行接口Closable接口的close()方法。

到此,已经把所有的销毁回调的执行都介绍完了。你是否看懂了呢??

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值