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

  • 一、注册bean销毁的类
    • 1.registerDisposableBeanIfNecessary()
    • 2.DisposableBeanAdapter
  • 二、调用过程
    • 1.contextDestroyed()
    • 2.closeWebApplicationContext()
    • 3.close(), doClose()
    • 4.destroySingletons()
    • 5.destroyBean()
    • 6.destroy()

上一章节中,我们跟完了bean的创建流程,而在创建完成以后,bean还会注册销毁相关的类,以便于像tomcat等容器关闭时相关的调用,本章我就聊这个。

一、注册bean销毁的类

先定位到类AbstractAutowireCapableBeanFactory的doCreateBean()方法

// Register bean as disposable.
try {//注册bean销毁时的类DisposableBeanAdapterregisterDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

1.registerDisposableBeanIfNecessary()

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);//非多例作用域并且要么有配置destroy-method或者要么有可用的DestructionAwareBeanPostProcessors后置处理器才会注册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.//DisposableBeanAdapter 对象就是负责bean 销毁的类。// 这个类中收集bean 是否实现了DisposableBean 接口registerDisposableBean(beanName,new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), 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, getBeanPostProcessors(), acc));}}
}

2.DisposableBeanAdapter

该类就是负责销毁bean的类,看下它的构造方法

public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,List<BeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {Assert.notNull(bean, "Disposable bean must not be null");this.bean = bean;this.beanName = beanName;this.invokeDisposableBean =(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();this.acc = acc;String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {this.destroyMethodName = destroyMethodName;Method destroyMethod = determineDestroyMethod(destroyMethodName);if (destroyMethod == null) {if (beanDefinition.isEnforceDestroyMethod()) {throw new BeanDefinitionValidationException("Could not find a destroy method named '" +destroyMethodName + "' on bean with name '" + beanName + "'");}}else {Class<?>[] paramTypes = destroyMethod.getParameterTypes();if (paramTypes.length > 1) {throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +beanName + "' has more than one parameter - not supported as destroy method");}else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +beanName + "' has a non-boolean parameter - not supported as destroy method");}destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);}this.destroyMethod = destroyMethod;}//过滤了DestructionAwareBeanPostProcessor 类型的接口this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
}

最主要干的事儿就是最后一步,收集DestructionAwareBeanPostProcessor 类型,放入列表当中

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) {//过滤了DestructionAwareBeanPostProcessor 类型的接口if (processor instanceof DestructionAwareBeanPostProcessor) {DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;if (dabpp.requiresDestruction(bean)) {filteredPostProcessors.add(dabpp);}}}}return filteredPostProcessors;
}

二、调用过程

目前主流服务端运行的java程序均为Servlet,并且通常都是在tomcat中,那bean的销毁通常与tomcat的关闭有关。我们知道servlet的生命周期有三大步骤:

  • init(): 初始化阶段
  • service(): 处理客户端请求阶段
  • destroy(): 终止阶段

destroy()阶段,相关监听监测到销毁事件,然后发起析构。定位到ContextLoaderListener类中的contextDestroyed()方法,看看是怎么一个过程。

1.contextDestroyed()

public void contextDestroyed(ServletContextEvent event) {//开始准备关闭WebApplicationContextcloseWebApplicationContext(event.getServletContext());ContextCleanupListener.cleanupAttributes(event.getServletContext());
}

2.closeWebApplicationContext()

//ContextLoader
public void closeWebApplicationContext(ServletContext servletContext) {servletContext.log("Closing Spring root WebApplicationContext");try {if (this.context instanceof ConfigurableWebApplicationContext) {//开始准备关闭WebApplicationContext((ConfigurableWebApplicationContext) this.context).close();}}finally {ClassLoader ccl = Thread.currentThread().getContextClassLoader();if (ccl == ContextLoader.class.getClassLoader()) {currentContext = null;}else if (ccl != null) {currentContextPerThread.remove(ccl);}servletContext.removeAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);}
}

点进去看看close()方法,调用的是AbstractApplicationContext的close()方法。

3.close(), doClose()

public 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}}}
}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.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.//开始发起调用销毁流程了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);}
}protected void destroyBeans() {getBeanFactory().destroySingletons();
}

而destroySingletons()实现类为DefaultSingletonBeanRegistry,点进去看看

4.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());}for (int i = disposableBeanNames.length - 1; i >= 0; i--) {//就是这里了destroySingleton(disposableBeanNames[i]);}this.containedBeanMap.clear();this.dependentBeanMap.clear();this.dependenciesForBeanMap.clear();clearSingletonCache();
}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);
}

5.destroyBean()

protected void destroyBean(String beanName, @Nullable DisposableBean bean) {// Trigger destruction of dependent beans first...Set<String> dependencies;synchronized (this.dependentBeanMap) {// Within full synchronization in order to guarantee a disconnected Setdependencies = this.dependentBeanMap.remove(beanName);}if (dependencies != null) {if (logger.isTraceEnabled()) {logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);}for (String dependentBeanName : dependencies) {destroySingleton(dependentBeanName);}}// Actually destroy the bean now...if (bean != null) {try {//真正销毁的地方,会调用到DisposableBeanAdapter中的destroy()方法bean.destroy();}catch (Throwable ex) {if (logger.isWarnEnabled()) {logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);}}}// Trigger destruction of contained beans...Set<String> containedBeans;synchronized (this.containedBeanMap) {// Within full synchronization in order to guarantee a disconnected SetcontainedBeans = 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);
}

6.destroy()

public void destroy() {if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {processor.postProcessBeforeDestruction(this.bean, this.beanName);}}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);}}}if (this.destroyMethod != null) {invokeCustomDestroyMethod(this.destroyMethod);}else if (this.destroyMethodName != null) {Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);if (methodToInvoke != null) {invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));}}
}

【Spring源码学习】Spring Bean的销毁相关推荐

  1. Spring源码解析之bean的销毁

    阅读须知 Spring源码版本:4.3.8 文章中使用/* */注释的方法会做深入分析 正文 我们来看几个销毁bean的场景,在一些异常情况,例如Spring上下文初始化失败时,会销毁已经创建的单例b ...

  2. 结合Spring源码学习单例设计模式

    之前我学习了 Spring Ioc,明白了 Spring IoC 容器是一个管理Bean的容器,在Spring的定义中,它要求所有的IoC容器都需要实现接口 BeanFactory ,它是一个顶级容器 ...

  3. spring源码学习之路---深入AOP(终)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...

  4. spring源码学习之整合Mybatis原理分析

    本文主要解析spring是如何与mybatis进行整合,整合的过程中需要哪些组件的支持.以前面提到过的配置例子<spring源码学习之aop事物标签解析> 整合的过程中需要使用以下这个依赖 ...

  5. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  6. Spring源码阅读之bean对象的创建过程

    Spring源码阅读之bean对象的创建过程 ​ Spring是通过IOC容器来管理对象的,该容器不仅仅只是帮我们创建了对象那么简单,它负责了对象的整个生命周期-创建.装配.销毁.这种方式成为控制反转 ...

  7. Spring源码学习(四) | @Configuration的cglib动态代理

    文章目录 前言 例子 @Configuration :full or lite 设置 full or lite Cglib生成代理类AppConfig Where is it generated Ho ...

  8. Spring源码学习的初步体会

    Spring源码学习的初步体会: 深入学习和巩固java的基础知识,其中的java知识范围全部,可以边研究源码边巩固复习基础知识 体会其中用到的设计思想:其中包含的设计原则和设计模式. 加深对spri ...

  9. Spring源码分析系列——bean创建过程分析(三)——工厂方法创建bean

    前言 spring创建bean的方式 测试代码准备 createBeanInstance()方法分析 instantiateUsingFactoryMethod()方法分析 总结 spring创建be ...

最新文章

  1. javaweb k8s_K8S微服务核心架构学习指南 ASP.NET Core微服务基于K8S 架构师必备Kubernetes教程...
  2. 神经网络 | BP神经网络介绍(附源代码:BP神经网络-异或问题)
  3. Java类加载器总结
  4. Java Collections CheckedCollection()方法与示例
  5. 【转】职业生涯30年的规划(经典)
  6. zabbix 脚本安装
  7. 虚拟化小白对VMcpu分配的理解
  8. 信号处理VMD 变分模态分解,示例+完整代码
  9. linux 文件目录对比,文件/目录对比:diff命令
  10. 谁说文艺青年开花店必亏,我用3年时间挣了20万
  11. Day01-python编程基础
  12. Ninth season sixteenth episode,Monica is gonna do a boob job???bigger?????
  13. win10系统过期或处于通知模式
  14. 7.5.3 QListWidgetItem条目视图介绍
  15. 如何用CNN玩转AlphaGo版的五子棋?
  16. 从万物归零到虚拟与现实交错
  17. 径向基函数拟合(RBF Fitting)
  18. 案例分享 | 数智化升级:红蜻蜓的转型之路(下)
  19. Java中的短路与运算和短路或运算
  20. 开发自己的搜索引擎--Lucene 2.0+Heriterx(目录)

热门文章

  1. Unity3D ——游戏开炮,开枪屏幕震动效果实现
  2. easyui+themeleaf 分页查询实现
  3. 半个生物专业的我,硕士要毕业了。读研三年到底值不值得?
  4. Pytorch线性回归
  5. Android - 应用安装、卸载、覆盖安装的广播及不生效原因解析
  6. 【数据结构】希尔排序
  7. python中转义符的用法_Python——转义符的使用及实例
  8. pyqt5+pyqtgraph绘制流程图
  9. 集团企业邮箱怎么选择?公司邮箱用哪个好?
  10. canny算子的python实现以及pytorch实现