SpringBoot关闭过程中是如何销毁一个DisposableBean的?

接上文SpringBoot关闭时都做了哪些事?,本文我们详细分析一下DisposableBean的destroy过程。

DefaultSingletonBeanRegistrydestroySingleton方法。

public void destroySingleton(String beanName) {
	// Remove a registered singleton of the given name, if any.
	// 从缓存中移除当前beanName
	removeSingleton(beanName);

	// Destroy the corresponding DisposableBean instance.
	// 从disposableBeans集合中移除当前 beanName
	DisposableBean disposableBean;
	synchronized (this.disposableBeans) {
		disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
	}
	// 这是核心方法
	destroyBean(beanName, disposableBean);
}

disposableBeans里面存放的是beanName以及对应的DisposableBeanAdapter实例。其他方法我们过一下即可,这里我们着重分析destroyBean(beanName, disposableBean);

【1】核心方法DefaultSingletonBeanRegistry的destroyBean

// DefaultSingletonBeanRegistry
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
	// Trigger destruction of dependent beans first...
	Set<String> dependencies;
	
	//dependentBeanMap存放的是哪些bean依赖于key
	synchronized (this.dependentBeanMap) {
		// Within full synchronization in order to guarantee a disconnected Set
		dependencies = this.dependentBeanMap.remove(beanName);
	}
	// 首先触发那些依赖于当前beanName的bean的销毁流程
	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...
	// bean销毁的过程入口,触发DisposableBeanAdapter的destroy方法
	if (bean != null) {
		try {
			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...
	// 获取当前beanName对应的containedBeans,如果有,则遍历触发销毁流程
	Set<String> containedBeans;
	synchronized (this.containedBeanMap) {
		// Within full synchronization in order to guarantee a disconnected Set
		containedBeans = this.containedBeanMap.remove(beanName);
	}
	if (containedBeans != null) {
		for (String containedBeanName : containedBeans) {
			destroySingleton(containedBeanName);
		}
	}

	// Remove destroyed bean from other beans' dependencies.
	// 遍历dependentBeanMap的value,移除掉当前beanName。
	//之后如果value为空,其从dependentBeanMap移除掉当前entry
	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.
	// 从 dependenciesForBeanMap中移除当前beanName对应的entry
	this.dependenciesForBeanMap.remove(beanName);
}

方法逻辑梳理如下:

  • 首先触发那些依赖于当前beanName的bean的销毁流程
  • bean.destroy();触发DisposableBeanAdapter的destroy方法
    • 获取当前实例维护的DestructionAwareBeanPostProcessor 触发其postProcessBeforeDestruction方法,如果有@PreDestroy注解的方法,这时会被触发。
    • 根据invokeDisposableBean判断是否触发destroy方法
    • 尝试触发其自定义destroy method
  • 获取当前beanName对应的containedBeans,如果有,则遍历触发销毁流程
  • 遍历dependentBeanMap的value,移除掉当前beanName。之后如果value为空,其从dependentBeanMap移除掉当前entry
  • dependenciesForBeanMap中移除当前beanName对应的entry

【2】DisposableBeanAdapter

上面提到了bean.destroy();触发DisposableBeanAdapter的destroy方法,方法如下所示:

@Override
public void destroy() {
//获取当前实例维护的DestructionAwareBeanPostProcessor 触发其postProcessBeforeDestruction方法
	if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
		for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
			processor.postProcessBeforeDestruction(this.bean, this.beanName);
		}
	}
// 是否触发destroy方法
	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);
			}
		}
	}
// 如果destroyMethod 不为null,则触发自定义销毁方法
	if (this.destroyMethod != null) {
		invokeCustomDestroyMethod(this.destroyMethod);
	}
	else if (this.destroyMethodName != null) {
	// 如果destroyMethodName 不为null,则获取并触发自定义销毁方法
		Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
		if (methodToInvoke != null) {
			invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
		}
	}
}

方法流程梳理如下 :

  • 获取当前实例维护的DestructionAwareBeanPostProcessor 触发其postProcessBeforeDestruction方法,如果有@PreDestroy注解的方法,这时会被触发。
  • 根据invokeDisposableBean判断是否触发destroy方法
  • 尝试触发其自定义destroy method
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值