资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

Spring之Bean生命周期源码解析-Bean销毁-创新互联

这篇文章是我在系统学习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, ClassbeanType, 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(Classclazz) {
		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元起,快前往官网查看详情吧


当前名称:Spring之Bean生命周期源码解析-Bean销毁-创新互联
本文网址:http://cdkjz.cn/article/cdohep.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220