十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
这篇文章是我在系统学习Spring源码之后,基于自己对Spring源码的理解,来详细分析Spring之Bean的销毁过程。
成都创新互联主营吉县网站建设的网络公司,主营网站建设方案,成都App定制开发,吉县h5小程序开发搭建,吉县网站营销推广欢迎吉县等地区企业咨询
目录
前言
一、注册有销毁逻辑的Bean
1.判断当前Bean是否需要销毁
1.1. 判断当前Bean是否有销毁方法
1.2. 判断有没有DestructionAwareBeanPostProcessor,并且DestructionAwareBeanPostProcessor.requiresDestruction()方法返回true
2.注册DisposableBean
二、Bean销毁过程
1.容器关闭
2.执行doClose()
在Bean创建的过程中,在最后(初始化之后),有一个步骤是去注册DisposableBean,原型Bean是不会注册成为DisposableBean的,因为Spring容器中是不会存原型Bean的,Spring是通过requiresDestruction()方法来判断该Bean是否需要销毁,对需要销毁的Bean,封装成DisposableBeanAdapter对象,最后调用registerDisposableBean()方法将DisposableBeanAdapter对象放入disposableBeans中,当Spring容器关闭的时候,可以直接从该map中取出定义了销毁逻辑的Bean,执行它们销毁的方法;
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
//requiresDestruction(bean, mbd),判断当前bean在销毁的时候是否要执行某些逻辑
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, getBeanPostProcessorCache().destructionAware, 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, getBeanPostProcessorCache().destructionAware, acc));
}
}
}
一、注册有销毁逻辑的Bean
1.判断当前Bean是否需要销毁protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
//判断当前bean在销毁时候,有没有定义有关销毁的某些方法,不是所有的bean在销毁的时候都要去执行有关销毁的逻辑
return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
(hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
bean, getBeanPostProcessorCache().destructionAware))));
}
1.1. 判断当前Bean是否有销毁方法1) 如果当前bean实现了DisposableBean或AutoCloseable接口,重写接口中的destroy()和close()方法,这两个方法都是销毁方法;
public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
return true;
}
return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
}
private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
if (destroyMethodName == null) {
destroyMethodName = beanDefinition.getDestroyMethodName();
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
destroyMethodName = null;
if (!(bean instanceof DisposableBean)) {
try {
destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
}
catch (NoSuchMethodException ex) {
try {
destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
}
catch (NoSuchMethodException ex2) {
// no candidate destroy method found
}
}
}
}
beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");
}
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
}
2)如果没有实现这两个接口,则判断当前Bean的RootBeanDefinition中是否设置了销毁方法的名字,设置销毁方法名有两种场景:
场景一:自定义的方法名字,Spring会将此方法的名字作为销毁方法的名字;
场景二:指定了特定的销毁方法的名字:"(inferred)",则会将该Bean中close()和shutdown()作为销毁方法(前提是Bean里面有这两个方法);
@Component
public class MyMergedBeanDefinitionPostProcessor1 implements MergedBeanDefinitionPostProcessor {
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class>beanType, String beanName) {
if (beanName.equals("xxx")) {
//设置Spring指定的特定的名字"(inferred)"
beanDefinition.setDestroyMethodName("(inferred)");、
//自定义销毁方法的名字
beanDefinition.setDestroyMethodName("customDestory");
}
}
}
初始化和销毁方法名都是在创建Bean过程中的合并后的BeanDefination的后置处理阶段设置的,即MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()中完成的。
1.2. 判断有没有DestructionAwareBeanPostProcessor,并且DestructionAwareBeanPostProcessor.requiresDestruction()方法返回true· DestructionAwareBeanPostProcessor接口主要用于Bean销毁,其中的requiresDestruction()判断Bean是否需要销毁,postProcessBeforeDestruction()是实现具体的销毁逻辑,而InitDestroyAnnotationBeanPostProcessor就是DestructionAwareBeanPostProcessor的一个具体实现;
· 这里主要针对@PreDestroy注解,它主要用来定义销毁方法(被该注解修饰的方法都是销毁方法),该注解的处理就是在InitDestroyAnnotationBeanPostProcessor类中完成,它会缓存每个Bean以及它的父类中被@PreDestroy修饰的方法;
public static boolean hasApplicableProcessors(Object bean, ListpostProcessors) {
if (!CollectionUtils.isEmpty(postProcessors)) {
for (DestructionAwareBeanPostProcessor processor : postProcessors) {
//确定给定的 bean实例,有没有定义销毁逻辑
if (processor.requiresDestruction(bean)) {
return true;
}
}
}
return false;
}
· @PostConstruct和@PreDestroy注解的扫描,是在buildLifecycleMetadata()方法中完成并进行分类缓存的,这一步骤在创建Bean过程中的初始化阶段就已完成,这里只需要判断是否有@PreDestroy定义的销毁方法,判断当前Bean是否需要销毁;
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;
}
2.注册DisposableBean注册销毁的Bean,disposableBeans中缓存的是DisposableBeanAdapter对象,而不是当前正在创建的Bean对象,无论该Bean是实现了DisposableBean或AutoCloseable接口,或者是通过BeanDifinition后置处理指定了”(inferred)“销毁方法名或其它名字的销毁方法, 还是通过@PreDestroy指定了销毁方法,这里都会将Bean适配成一个DisposableBeanAdapter对象;
// 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, getBeanPostProcessorCache().destructionAware, acc));
public void registerDisposableBean(String beanName, DisposableBean bean) {
synchronized (this.disposableBeans) {
this.disposableBeans.put(beanName, bean);
}
说明:这里涉及到一个设计模式:适配器模式 ,在销毁时,Spring会找出定义了销毁逻辑的Bean。 但是我们在定义一个Bean时,如果这个Bean实现了DisposableBean接口,或者实现了 AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么这个Bean都属 于“DisposableBean”,这些Bean在容器关闭时都要调用相应的销毁方法。 所以,这里就需要进行适配,将实现了DisposableBean接口、或者AutoCloseable接口等适配成实现了DisposableBean接口,所以就用到了DisposableBeanAdapter。
DisposableBeanAdapter的构造方法
在DisposableBeanAdapter的构造方法中,会推断出销毁方法,并过滤出所有实现了DestructionAwareBeanPostProcessor接口且requiresDestruction()方法返回true的DestructionAwareBeanPostProcessor,销毁的时候会调用它们的postProcessBeforeDestruction()方法;
public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
ListpostProcessors, @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 {
if (destroyMethod.getParameterCount() >0) {
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;
}
this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
}
private static ListfilterPostProcessors(
Listprocessors, Object bean) {
ListfilteredPostProcessors = null;
if (!CollectionUtils.isEmpty(processors)) {
filteredPostProcessors = new ArrayList<>(processors.size());
for (DestructionAwareBeanPostProcessor processor : processors) {
if (processor.requiresDestruction(bean)) {
filteredPostProcessors.add(processor);
}
}
}
return filteredPostProcessors;
}
二、Bean销毁过程
1.容器关闭在Spring容器关闭的时候,会去销毁所有的单例Bean,只要是单例对象,不管有没有定义销毁的逻辑,都是要销毁的,只是定义了销毁逻辑的单例Bean在销毁之前,Spring会调用它们定义的销毁逻辑,Spring容器关闭触发Bean销毁的两种方式,如下:
ApplicationContext context= new AnnotationConfigApplicationContext(AppConfig.class);
//spring容器关闭的时候,会触发销毁方法
context.close();
//不用手动调用context.close()方法,可以向JVM里面注册一个关闭钩子,这样也可以触发销毁方法,,这个关闭钩子就是一个线程
context.registerShutdownHook();
以上两种方式,都会调用doClose(),doClose()会去调执行销毁Bean的方法。
2.执行doClose()doClose()中会调用destroyBeans(),而在destroySingletons()中会取出disposableBeans缓存中定义了销毁逻辑的Bean的beanName,然后遍历进行销毁
protected void destroyBeans() {
getBeanFactory().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();
}
在进行销毁的时候,先从单例池等缓存中移除Bean,然后从disposableBeans移除当前DisposableBean并获取该对象,最后调用destroyBean(beanName, disposableBean)执行对象的销毁逻辑;在销毁当前Bean的时候,会获取依赖当前Bean的其他Bean的beanName,然后递归调用destroySingleton()方法,保证依赖当前Bean的其他Bean先销毁,在进行销毁时,会先调用DisposableBean的destroy()方法,然后再去调用其它的销毁逻辑,其它的销毁逻辑基本就是从各种缓存中根据BeanName,清除缓存;
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, @Nullable DisposableBean bean) {
// dependentBeanMap表示某bean被哪些bean依赖了
// 所以现在要销毁某个bean时,如果这个Bean还被其他Bean依赖了,那么也得销毁其他Bean
// Trigger destruction of dependent beans first...
Setdependencies;
synchronized (this.dependentBeanMap) {
// Within full synchronization in order to guarantee a disconnected Set
dependencies = 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对象的destory方法
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...
SetcontainedBeans;
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.
synchronized (this.dependentBeanMap) {
for (Iterator>>it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
Map.Entry>entry = it.next();
SetdependenciesToClean = entry.getValue();
dependenciesToClean.remove(beanName);
if (dependenciesToClean.isEmpty()) {
it.remove();
}
}
}
// Remove destroyed bean's prepared dependency information.
this.dependenciesForBeanMap.remove(beanName);
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧