目录

  • 前言
    • 回顾 `doCreateBean()` 方法
  • `registerDisposableBeanIfNecessary()` 方法概览
    • `requiresDestruction()` 方法重点
      • 给 `bean` 设置销毁方法的方式
      • 检查是否有 `DestructionAwareBeanPostProcessor` 实现类
  • `registerDisposableBeanIfNecessary()` 方法小结
    • 什么样的 `bean` 才能销毁
  • `spring` 注册关闭钩子 `ShutdownHook`
    • `registerShutdownHook()` 方法
    • `destroyBeans()` 方法
    • `destroySingletons()` 方法
    • `destroySingletons()` 方法
    • `destroy()` 方法

前言

这篇文章是 IOC 容器初始化启动时,抽象类 AbstractAutowireCapableBeanFactorydoCreateBean() 方法里面的 registerDisposableBeanIfNecessary() 方法,它是进行 bean 的销毁的方法

阅读本篇文章,同时可以参考阅读 spring源码之getBean(获取 bean)方法解读(二) 和 Spring Aop代理对象的产生(一) 这两篇文章的 doCreateBean() 方法

回顾 doCreateBean() 方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// BeanWrapper封装了具体的Bean实例,然后可以很方便地通过调用getPropertyValue和setPropertyValue等方法反射读写Bean的具体属性BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {// 先尝试从缓存中取instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {// 调用构造方法创建一个空实例对象,并用BeanWrapper进行包装instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// 获取所有的后置处理器,如果后置处理器实现了MergedBeanDefinitionPostProcessor接口,则一次调用其postProcessMergedBeanDefinition方法synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// 如果满足循环依赖缓存条件,先缓存具体对象boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isDebugEnabled()) {logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}/*** 循环依赖处理逻辑:将已完成实例化,但是未完成属性赋值和相关的初始化的一个不完整的 bean 添加到三级缓存 singletonFactories 中* 具体内部会遍历后置处理器,判断是否有SmartInstantiationAwareBeanPostProcessor的实现类,然后调用里面getEarlyBeanReference覆盖当前Bean* 默认不做任何操作返回当前Bean,作为拓展,这里比如可以供AOP来创建代理类*/addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 开始对Bean实例进行初始化Object exposedObject = bean;try {// 对bean进行属性填充,在这里面完成依赖注入的相关内容populateBean(beanName, mbd, instanceWrapper);// 完成属性依赖注入后,进一步初始化Bean// 具体进行了以下操作:// 1.若实现了BeanNameAware, BeanClassLoaderAware,BeanFactoryAwareAware等接口,则注入相关对象// 2.遍历后置处理器,调用实现的postProcessBeforeInitialization方法,// 3.如果实现了initialzingBean,调用实现的 afterPropertiesSet()// 4.如果配置了init-mothod,调用相应的init方法// 5.遍历后置处理器,调用实现的postProcessAfterInitializationexposedObject = 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);}}if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// 如果实现了Disposable接口,会在这里进行注册,最后在销毁的时候调用相应的destroy方法try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;
}

doCreateBean(beanName, mbd, args) 的主要方法流程:(重点)

  • createBeanInstance(beanName, mbd, args):实例化 bean
  • addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)):将已完成实例化,但是未完成属性赋值和相关的初始化的一个不完整的 bean 添加到三级缓存 singletonFactories
  • populateBean(beanName, mbd, instanceWrapper):对 bean 进行属性填充注入
  • initializeBean(beanName, exposedObject, mbd):完成 bean 的属性填充注入后,进一步初始化 bean,在此过程中产生代理对象。此时 bean 的创建工作正式完成,已经可以在项目中使用了
    -registerDisposableBeanIfNecessary(beanName, bean, mbd):如果符合 bean 的销毁条件,则执行单例bean 的销毁工作

registerDisposableBeanIfNecessary() 方法概览

它的具体调用是在 AbstractBeanFactory 中的 registerDisposableBeanIfNecessary() 方法

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);// 当前 bean 的作用域不是 Prototype && requiresDestruction 返回 trueif (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {// bean 的作用域是单例的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));}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));}}
}

requiresDestruction() 方法重点

protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {return (bean.getClass() != NullBean.class &&(DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
}

可以看到 requiresDestruction() 方法只要满足下面任意一个即可

  • hasDestroyMethod():检查给定 bean 是否有任何类型的 destroy 销毁的方法可调用
  • hasApplicableProcessors():检查是否有 DestructionAwareBeanPostProcessor 的实现类,并且 requiresDestruction() 方法返回 true

bean 设置销毁方法的方式

  • 通过 xml 文件配置 destroy-method 标签属性指定的 destroy 方法
  • 通过注解 @Bean 可以使用属性指定销毁的方法
  • 实现 DisposableBean 接口
  • 销毁方法名为接口情况下, 有 close 或者 shutdown 方法

检查是否有 DestructionAwareBeanPostProcessor 实现类

  • 实现了 ApplicationListener 接口
  • 方法加上了 @PreDestroy 注解

registerDisposableBeanIfNecessary() 方法小结

  • bean 的作用域不是 Prototype,同时给 bean 设置了销毁方法或有 DestructionAwareBeanPostProcessor 实现类
  • 在满足了上述条件之后,如果 bean 的作用域是单例的时,创建DisposableBeanAdapter 进行注册(添加到 disposableBeans 集合 LinkedHashMap 中)
// DefaultSingletonBeanRegistry 的属性
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();

什么样的 bean 才能销毁

  • bean 的作用域是单例时
  • bean 设置了销毁方法或有 DestructionAwareBeanPostProcessor 实现类时

spring 注册关闭钩子 ShutdownHook

spring 会先去调用注册的关闭钩子 ShutdownHook,通过这个方式进行销毁前的动作处理

public SpringApplicationBuilder registerShutdownHook(boolean registerShutdownHook) {this.registerShutdownHookApplied = true;this.application.setRegisterShutdownHook(registerShutdownHook);return this;
}

registerShutdownHook() 方法

该方法在 AbstractApplicationContext 类中

@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);}
}

destroyBeans() 方法

AbstractApplicationContext 类的 destroyBeans() 方法

protected void destroyBeans() {getBeanFactory().destroySingletons();
}

destroySingletons() 方法

DefaultListableBeanFactory 类中的 destroySingletons() 方法

@Override
public void destroySingletons() {super.destroySingletons();this.manualSingletonNames.clear();clearByTypeCache();
}

destroySingletons() 方法

DefaultSingletonBeanRegistry 类中的 destroySingletons() 方法

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 {// 调用 DisposableBeanAdapter 的 destroy()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);
}

流程总结为

  • 取出需要执行销毁方法的 bean(前面添加到了 disposableBeans中)
// DefaultSingletonBeanRegistry 的属性
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
  • 遍历每个 bean 执行销毁方法
  • 取出 bean 的依赖方,先销毁依赖方(就是之前 bean 装配提到的 @DependsOn 标志的依赖方)
  • 执行 beandestroy 销毁方法,包括下面 4
    1. 调用 DestructionAwareBeanPostProcessor 来执行销毁方法
    2. 执行 DisposableBeandestroy 方法
    3. 执行 init-method 指定的 destroy 方法
    4. 执行 @Bean 属性指定的 destroy 方法
  • 销毁内部类对象
  • 从依赖关系中去掉自己

destroy() 方法

DisposableBeanAdapterdestroy() 方法

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的销毁registerDisposableBeanIfNecessary方法解读相关推荐

  1. Spring源码解析-bean实例化

    Spring源码解析-bean实例化 ​ 本文介绍Spring创建 bean 过程中的第一个步骤:实例化 bean. 1. Bean实例化源码 ​ 虽然实例化Bean有多种方式(包括静态工厂和工厂实例 ...

  2. Spring 源码解析 - Bean创建过程 以及 解决循环依赖

    一.Spring Bean创建过程以及循环依赖 上篇文章对 Spring Bean资源的加载注册过程进行了源码梳理和解析,我们可以得到结论,资源文件中的 bean 定义信息,被组装成了 BeanDef ...

  3. Spring源码深度解析,Spring源码以及Bean的生命周期(五)(附代码示例:)

    五)Bean 的生命周期,创建---初始化---销毁的过程 目录 五)Bean 的生命周期,创建---初始化---销毁的过程 一 ,  指定初始化方法 init-method 方法​ 二 ,指定销毁 ...

  4. Spring源码剖析——Bean的配置与启动

    IOC介绍   相信大多数人在学习Spring时 IOC 和 Bean 算得上是最常听到的两个名词,IOC在学习Spring当中出现频率如此之高必然有其原因.如果我们做一个比喻的话,把Bean说成Sp ...

  5. Spring源码之Bean的注册(使用XML配置的方式)

    本文分析的Spring源码是5.2.2版本,使用Gradle进行管理. 一.Bean的注册,先来看通过XML配置Bean的方式 1.配置applicationContext.xml: <?xml ...

  6. 一、如何阅读Spring源码(全网最简单的方法)

    学习Java最好最有效的方法是学习Spring,但是最笨最没效的方法也是学习Spring. 为什么这么说呢?道理其实很简单 A.Spring很庞大,很完善,也非常的底层,如果我们学会的Spring,那 ...

  7. Spring源码分析——Bean的生命周期

    文章目录 说明 测试代码 说明 本文从源码的角度分析Spring中Bean的加载过程,本文使用的Spring版本为4.3.25.RELEASE 测试代码 测试代码如下,根据这段简单的测试代码,一步步跟 ...

  8. 三 spring源码解析--- Bean解析接口结构分析

    2019独角兽企业重金招聘Python工程师标准>>> 解析Bean是通过定义抽象的bean reader来解析,结构图如下 1.AbstractBeanDefinitionRead ...

  9. Spring源码之Bean的注册(注解方式)

    1.创建AnnotationConfigApplicationContext AnnotationConfigApplicationContext context = new AnnotationCo ...

  10. Spring源码学习--Bean的生命周期

    Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...

最新文章

  1. 深度学习如何挑选GPU?
  2. linux-----shell高级编程----sed应用
  3. java8中Predicate用法
  4. 【python opencv 计算机视觉零基础到实战】二、 opencv文件格式与摄像头读取
  5. 汇编语言-018(FLD 、FST、FSTP、FCHS、FABS 、浮点运算符、浮点比较 )
  6. 编译 linux 3,linux内核的编译(3)
  7. UVA - 133 ​​​​​​​The Dole Queue
  8. 使用getApplication()作为上下文的对话框抛出“无法添加窗口-令牌null不适用于应用程序”
  9. 【ACL2020放榜!】事件抽取、关系抽取、NER、Few-Shot 相关论文整理
  10. 锁 公平 非公平_推荐引擎也需要公平!
  11. 数据库系统概念第四章习题答案
  12. 淘宝爬登录、取个人资料、微博绑定、收货地址、支付宝绑定设置、安全设置等信息、购物车、收藏宝贝和店铺、个人积分、退款维权、我的足迹...
  13. ROS_Noetic使用handeye-calib进行机械臂手眼标定
  14. ios 渐变透明背景_PPT设计的总是太单调,不如换个背景试试,超精彩!
  15. MATLAB/Simulink当真,开环Buck、闭环Buck、双闭环Buck仿真;开环控制的半桥LLC谐振变换器,全桥LLC谐振变换器和电压闭环控制的半桥LLC
  16. STM32F407 FSMC驱动MT29F4G08A NAND FLASH源代码分享
  17. ffmpeg批量处理视频和音频合成
  18. excel查找出不来了_Excel查找值不唯一,一个VLOOKUP公式拖拉出多个结果啦
  19. Flink DataStream API(基础版)
  20. AR | 增强现实简述

热门文章

  1. 翻译: 3.2. 从零开始实现线性回归 深入神经网络 pytorch
  2. 极客大学架构师训练营 系统架构 一致性哈希 Consistent Hashing 第五次作业
  3. 算法:Reverse Linked List
  4. jupyter notebook添加虚拟环境
  5. 用tensorflow实现线性回归算法
  6. gis投影中未定义的地理转换_PhotoScan中经纬度转换为投影坐标快捷方法
  7. 验证服务器的通用性,通用VNFM部署的可行性分析与验证
  8. linux的abrt目录满了,linux:abrt-cli list
  9. 【机器学习系列】GMM第一讲:两个角度认识高斯混合模型
  10. 用Tensorflow基于Deep Q Learning DQN 玩Flappy Bird