登记需要执行销毁方法的bean

在bean装配里面提过,bean初始化完成之后,会注册成为添加到disposableBeans,这个disposableBeans就是在关闭的时候,调用其destroy方法来销毁bean

AbstractBeanFactory#registerDisposableBeanIfNecessary
重点是requiresDestruction方法,用来判断是否需要手动调用销毁方法,进去后发现有2个判断条件,满足任意一个即可:

  • 是否有销毁方法:

    • 通过destroy-method指定的destroy方法
    • 实现了DisposableBean接口
    • 销毁方法名为(inferred)情况下, 有close或者shutdown方法
  • 有DestructionAwareBeanPostProcessor实现类,并且DestructionAwareBeanPostProcessor#requiresDestruction判断满足条件(可通过实现DestructionAwareBeanPostProcessor接口来扩展)
    • 实现了ApplicationListener
    • scheduledTasks定时任务里面存在
    • 实现了Servlet
    • 有方法加上了@PreDestroy注解

如果满足条件,创建DisposableBeanAdapter进行注册(添加到disposableBeans)

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.registerDisposableBean(beanName,new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));}...}
}protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {return (bean != null &&(DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
}

第二个判断条件一下看上去有点看不懂,实际上它是提供一个可扩展的方式来决定是否需要手动执行销毁动作,我们来看下他目前的实现类,

另外3个都是比较简单的一个判断,

我们来主要看下CommonAnnotationBeanPostProcessor,发现他实现了InstantiationAwareBeanPostProcessor接口,对的,就是bean构建过程中会进行调用,下面来看做了啥

首先,初始化的时候,设置了setDestroyAnnotationType(PreDestroy.class)

在对象构建完后,调用其postProcessMergedBeanDefinition方法时,会遍历对象的方法找出用于销毁的方法存到destroyMethods(根据setDestroyAnnotationType设置的类型),最后就可以用来判断该对象是否需要销毁动作以及具体销毁的动作的执行

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {...public CommonAnnotationBeanPostProcessor() {setOrder(Ordered.LOWEST_PRECEDENCE - 3);setInitAnnotationType(PostConstruct.class);setDestroyAnnotationType(PreDestroy.class);ignoreResourceType("javax.xml.ws.WebServiceContext");}...// 父类方法@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);if (beanType != null) {InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);}}...public boolean requiresDestruction(Object bean) {return findLifecycleMetadata(bean.getClass()).hasDestroyMethods();}// 父类方法private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {if (this.lifecycleMetadataCache == null) {// Happens after deserialization, during destruction...return buildLifecycleMetadata(clazz);}// Quick check on the concurrent map first, with minimal locking.LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);if (metadata == null) {synchronized (this.lifecycleMetadataCache) {metadata = this.lifecycleMetadataCache.get(clazz);if (metadata == null) {metadata = buildLifecycleMetadata(clazz);this.lifecycleMetadataCache.put(clazz, metadata);}return metadata;}}return metadata;}// 父类方法private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {final boolean debug = logger.isDebugEnabled();LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();Class<?> targetClass = clazz;do {final LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();final LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {@Overridepublic void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {if (initAnnotationType != null) {if (method.getAnnotation(initAnnotationType) != null) {LifecycleElement element = new LifecycleElement(method);currInitMethods.add(element);if (debug) {logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);}}}if (destroyAnnotationType != null) {if (method.getAnnotation(destroyAnnotationType) != null) {currDestroyMethods.add(new LifecycleElement(method));if (debug) {logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);}}}}});initMethods.addAll(0, currInitMethods);destroyMethods.addAll(currDestroyMethods);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return new LifecycleMetadata(clazz, initMethods, destroyMethods);}...
}

注册关闭钩子ShutdownHook

之前 JVM关闭 里面说过,程序正常关闭的时候,JVM会先去调用注册的关闭钩子ShutdownHook,spring也是通过这个方式进行销毁前的动作处理

SpringApplication#createAndRefreshContext
AbstractApplicationContext#registerShutdownHook
在完成上下文创建后,会注册关闭钩子

@Override
public void registerShutdownHook() {if (this.shutdownHook == null) {// No shutdown hook registered yet.this.shutdownHook = new Thread() {@Overridepublic void run() {synchronized (startupShutdownMonitor) {doClose();}}};Runtime.getRuntime().addShutdownHook(this.shutdownHook);}
}protected void doClose() {if (this.active.get() && this.closed.compareAndSet(false, true)) {if (logger.isInfoEnabled()) {logger.info("Closing " + this);}LiveBeansView.unregisterApplicationContext(this);try {// Publish shutdown event.// 发布上下文关闭事件ContextClosedEventpublishEvent(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.// 调用Lifecycle#stop方法try {getLifecycleProcessor().onClose();}catch (Throwable ex) {logger.warn("Exception thrown from LifecycleProcessor on context close", ex);}// Destroy all cached singletons in the context's BeanFactory.// 销毁beandestroyBeans();// Close the state of this context itself.closeBeanFactory();// Let subclasses do some final clean-up if they wish...onClose();this.active.set(false);}
}

bean销毁

再来具体看bean销毁的方法
AbstractApplicationContext#destroyBeans
DefaultListableBeanFactory#destroySingletons
DefaultSingletonBeanRegistry#destroySingletons

流程总结为:

  1. 取出需要执行销毁方法的bean(前面注册登记的)
  2. 遍历每个bean执行销毁方法
  3. 取出bean的依赖方,先销毁依赖方(就是之前bean装配提到的@DependsOn标志的依赖方)
  4. 执行bean的destroy方法:
    4.1. 调用DestructionAwareBeanPostProcessor来执行销毁方法
    4.2. 执行DisposableBean#destroy方法
    4.3. 执行init-method指定的destroy方法
  5. 销毁内部类对象
  6. 从依赖关系中去掉自己
public void destroySingletons() {if (logger.isDebugEnabled()) {logger.debug("Destroying singletons in " + this);}synchronized (this.singletonObjects) {this.singletonsCurrentlyInDestruction = true;}String[] disposableBeanNames;synchronized (this.disposableBeans) {disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());}for (int i = disposableBeanNames.length - 1; i >= 0; i--) {destroySingleton(disposableBeanNames[i]);}this.containedBeanMap.clear();this.dependentBeanMap.clear();this.dependenciesForBeanMap.clear();synchronized (this.singletonObjects) {this.singletonObjects.clear();this.singletonFactories.clear();this.earlySingletonObjects.clear();this.registeredSingletons.clear();this.singletonsCurrentlyInDestruction = false;}
}public void destroySingleton(String beanName) {// Remove a registered singleton of the given name, if any.removeSingleton(beanName);// Destroy the corresponding DisposableBean instance.DisposableBean disposableBean;synchronized (this.disposableBeans) {disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);}destroyBean(beanName, disposableBean);
}protected void destroyBean(String beanName, DisposableBean bean) {// Trigger destruction of dependent beans first...Set<String> dependencies = this.dependentBeanMap.remove(beanName);if (dependencies != null) {if (logger.isDebugEnabled()) {logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);}for (String dependentBeanName : dependencies) {destroySingleton(dependentBeanName);}}// Actually destroy the bean now...if (bean != null) {try {bean.destroy();}catch (Throwable ex) {logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);}}// Trigger destruction of contained beans...Set<String> containedBeans = this.containedBeanMap.remove(beanName);if (containedBeans != null) {for (String containedBeanName : containedBeans) {destroySingleton(containedBeanName);}}// Remove destroyed bean from other beans' dependencies.synchronized (this.dependentBeanMap) {for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {Map.Entry<String, Set<String>> entry = it.next();Set<String> dependenciesToClean = entry.getValue();dependenciesToClean.remove(beanName);if (dependenciesToClean.isEmpty()) {it.remove();}}}// Remove destroyed bean's prepared dependency information.this.dependenciesForBeanMap.remove(beanName);
}

DisposableBeanAdapter#destroy

public void destroy() {if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {// 调用DestructionAwareBeanPostProcessor来执行销毁方法,就是上文提到的for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {processor.postProcessBeforeDestruction(this.bean, this.beanName);}}if (this.invokeDisposableBean) {if (logger.isDebugEnabled()) {logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");}try {// 执行DisposableBean#destroy方法if (System.getSecurityManager() != null) {AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {@Overridepublic Object run() throws Exception {((DisposableBean) bean).destroy();return null;}}, acc);}else {((DisposableBean) 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);}}}// 执行destroy-method指定的销毁方法if (this.destroyMethod != null) {invokeCustomDestroyMethod(this.destroyMethod);}else if (this.destroyMethodName != null) {Method methodToCall = determineDestroyMethod();if (methodToCall != null) {invokeCustomDestroyMethod(methodToCall);}}
}

spring:bean的销毁相关推荐

  1. 【Spring源码学习】Spring Bean的销毁

    [Spring源码学习]Spring Bean的销毁 一.注册bean销毁的类 1.registerDisposableBeanIfNecessary() 2.DisposableBeanAdapte ...

  2. spring bean的初始化和销毁

    为什么80%的码农都做不了架构师?>>>    spring bean的初始化和销毁有3种形式: 1.通过注解@PostConstruct 和 @PreDestroy 方法实现初始化 ...

  3. spring bean初始化及销毁你必须要掌握的回调方法。

    转载自 spring bean初始化及销毁你必须要掌握的回调方法. spring bean在初始化和销毁的时候我们可以触发一些自定义的回调操作. 初始化的时候实现的方法 1.通过java提供的@Pos ...

  4. spring Bean的初始化和销毁 (使用注解)

    使用注解定义Bean的初始化和销毁 Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法. 回顾配置文件的写 ...

  5. Spring中初始化bean和销毁bean的时候执行某个方法的详解

    关于在spring  容器初始化 bean 和销毁前所做的操作定义方式有三种: 第一种:通过注解@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作 ...

  6. spring Bean的初始化和销毁生命周期方法

    使用注解定义Bean的初始化和销毁 Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法. 回顾配置文件的写 ...

  7. Spring Bean配置方式之一:Java配置

    简介: Spring bean 是使用传统的 XML 方法配置的.在这篇文章中,您将学习使用基于纯 Java 的配置而非 XML 来编写 Spring bean 并配置它们.本文将介绍可用来配置 be ...

  8. Spring ----Bean的生命周期

    这Spring框架中,一旦把一个bean纳入到Spring IoC容器之中,这个bean的生命周期就会交由容器进行管理, 一般担当管理者角色的是BeanFactory或ApplicationConte ...

  9. 【一步一步学习spring】spring bean管理(上)

    1. spring 工厂类 我们前边的demo中用到的spring 工厂类是ClassPathXmlApplicationContext,从上图可以看到他还有一个兄弟类FileSystemApplic ...

最新文章

  1. Python并发之协程gevent基础(5)
  2. SpringBoot------Servlet3.0的注解自定义原生Listener监听器
  3. spring的applicationContext.xml如何自动加载
  4. linux下tmp目录属性,Linux:文件夹属性及umask
  5. WindowsMobile应该如何发展?(未完待续)
  6. 根据个人亲身进阶架构师经历系统构建20大进阶架构师专题!
  7. bpython_Python机器学习(入门)
  8. 一个不错的验证码的例子
  9. c语言迷宫源码,C语言迷宫源代码
  10. 【POJ1328】Radar Installation(贪心,决策包容)
  11. java filewriter写入文件_Java中的写入字符文件类FileWriter
  12. 软件授权注册码_授权码授予
  13. 博客群建软件-关键词要如何优化才能有好的排名
  14. 利用matlab命令窗口绘制simulink仿真示波器波形的方法,利用MATLAB命令窗口绘制Simulink仿真示波器波形的方法...
  15. 奇异值分解(SVD)
  16. S5P4418裸机开发(六):串口初试,简单回显(轮询模式)
  17. 镍基合金600材质,用什么配套焊材 by阿斯米合金
  18. 如何在Word,excel 中打钩和打叉?
  19. 基于Python热点新闻关键词数据分析系统
  20. android6.0-nexus5 mac上docker 编译刷机

热门文章

  1. 今天给大家分享一个HTML5的钢琴代码,可以弹奏的哦!(附完整源码)
  2. 研报精选230504
  3. Android Studio初学者实例:仿拼多多砍价页面
  4. flutter 布局 Stack Positioned的混合操作 两个组件Container重叠 构建背景圆角操作 类似css的relative
  5. 导出带图片的excel
  6. 计算机质量保障体系及措施,计算机科学和技术专业质量保障体系(2016_11_25).doc...
  7. 开发过程中js遇到的问题及一些基础知识恶补
  8. 服务器完整备份是最简单的备份形式
  9. Collection 接口(含迭代器)
  10. Docker容器原理详解