Spring之Bean生命周期源碼解析-Bean銷毀-創(chuàng)新互聯(lián)

這篇文章是我在系統(tǒng)學(xué)習(xí)Spring源碼之后,基于自己對Spring源碼的理解,來詳細(xì)分析Spring之Bean的銷毀過程。

成都創(chuàng)新互聯(lián)主營吉縣網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都App定制開發(fā),吉縣h5小程序開發(fā)搭建,吉縣網(wǎng)站營銷推廣歡迎吉縣等地區(qū)企業(yè)咨詢

目錄

前言

一、注冊有銷毀邏輯的Bean

1.判斷當(dāng)前Bean是否需要銷毀

1.1. 判斷當(dāng)前Bean是否有銷毀方法

1.2.?判斷有沒有DestructionAwareBeanPostProcessor,并且DestructionAwareBeanPostProcessor.requiresDestruction()方法返回true

2.注冊DisposableBean

二、Bean銷毀過程

1.容器關(guān)閉

2.執(zhí)行doClose()


前言

在Bean創(chuàng)建的過程中,在最后(初始化之后),有一個步驟是去注冊DisposableBean,原型Bean是不會注冊成為DisposableBean的,因為Spring容器中是不會存原型Bean的,Spring是通過requiresDestruction()方法來判斷該Bean是否需要銷毀,對需要銷毀的Bean,封裝成DisposableBeanAdapter對象,最后調(diào)用registerDisposableBean()方法將DisposableBeanAdapter對象放入disposableBeans中,當(dāng)Spring容器關(guān)閉的時候,可以直接從該map中取出定義了銷毀邏輯的Bean,執(zhí)行它們銷毀的方法;

protected void  registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
		//requiresDestruction(bean, mbd),判斷當(dāng)前bean在銷毀的時候是否要執(zhí)行某些邏輯
		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.判斷當(dāng)前Bean是否需要銷毀
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
		//判斷當(dāng)前bean在銷毀時候,有沒有定義有關(guān)銷毀的某些方法,不是所有的bean在銷毀的時候都要去執(zhí)行有關(guān)銷毀的邏輯
		return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
				(hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
						bean, getBeanPostProcessorCache().destructionAware))));
	}
1.1. 判斷當(dāng)前Bean是否有銷毀方法

1) 如果當(dāng)前bean實現(xiàn)了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)如果沒有實現(xiàn)這兩個接口,則判斷當(dāng)前Bean的RootBeanDefinition中是否設(shè)置了銷毀方法的名字,設(shè)置銷毀方法名有兩種場景:

場景一:自定義的方法名字,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")) {
            //設(shè)置Spring指定的特定的名字"(inferred)"
			beanDefinition.setDestroyMethodName("(inferred)");、
            //自定義銷毀方法的名字
			beanDefinition.setDestroyMethodName("customDestory");
		}
	}

}

初始化和銷毀方法名都是在創(chuàng)建Bean過程中的合并后的BeanDefination的后置處理階段設(shè)置的,即MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()中完成的。

1.2.?判斷有沒有DestructionAwareBeanPostProcessor,并且DestructionAwareBeanPostProcessor.requiresDestruction()方法返回true

· DestructionAwareBeanPostProcessor接口主要用于Bean銷毀,其中的requiresDestruction()判斷Bean是否需要銷毀,postProcessBeforeDestruction()是實現(xiàn)具體的銷毀邏輯,而InitDestroyAnnotationBeanPostProcessor就是DestructionAwareBeanPostProcessor的一個具體實現(xiàn);

·?這里主要針對@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()方法中完成并進(jìn)行分類緩存的,這一步驟在創(chuàng)建Bean過程中的初始化階段就已完成,這里只需要判斷是否有@PreDestroy定義的銷毀方法,判斷當(dāng)前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對象,而不是當(dāng)前正在創(chuàng)建的Bean對象,無論該Bean是實現(xiàn)了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);
}
	

說明:這里涉及到一個設(shè)計模式:適配器模式 ,在銷毀時,Spring會找出定義了銷毀邏輯的Bean。 但是我們在定義一個Bean時,如果這個Bean實現(xiàn)了DisposableBean接口,或者實現(xiàn)了 AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么這個Bean都屬 于“DisposableBean”,這些Bean在容器關(guān)閉時都要調(diào)用相應(yīng)的銷毀方法。 所以,這里就需要進(jìn)行適配,將實現(xiàn)了DisposableBean接口、或者AutoCloseable接口等適配成實現(xiàn)了DisposableBean接口,所以就用到了DisposableBeanAdapter。

DisposableBeanAdapter的構(gòu)造方法

在DisposableBeanAdapter的構(gòu)造方法中,會推斷出銷毀方法,并過濾出所有實現(xiàn)了DestructionAwareBeanPostProcessor接口且requiresDestruction()方法返回true的DestructionAwareBeanPostProcessor,銷毀的時候會調(diào)用它們的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.容器關(guān)閉

在Spring容器關(guān)閉的時候,會去銷毀所有的單例Bean,只要是單例對象,不管有沒有定義銷毀的邏輯,都是要銷毀的,只是定義了銷毀邏輯的單例Bean在銷毀之前,Spring會調(diào)用它們定義的銷毀邏輯,Spring容器關(guān)閉觸發(fā)Bean銷毀的兩種方式,如下:

ApplicationContext context= new AnnotationConfigApplicationContext(AppConfig.class);
//spring容器關(guān)閉的時候,會觸發(fā)銷毀方法
context.close();
//不用手動調(diào)用context.close()方法,可以向JVM里面注冊一個關(guān)閉鉤子,這樣也可以觸發(fā)銷毀方法,,這個關(guān)閉鉤子就是一個線程
context.registerShutdownHook();

以上兩種方式,都會調(diào)用doClose(),doClose()會去調(diào)執(zhí)行銷毀Bean的方法。

2.執(zhí)行doClose()

doClose()中會調(diào)用destroyBeans(),而在destroySingletons()中會取出disposableBeans緩存中定義了銷毀邏輯的Bean的beanName,然后遍歷進(jìn)行銷毀

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

在進(jìn)行銷毀的時候,先從單例池等緩存中移除Bean,然后從disposableBeans移除當(dāng)前DisposableBean并獲取該對象,最后調(diào)用destroyBean(beanName, disposableBean)執(zhí)行對象的銷毀邏輯;在銷毀當(dāng)前Bean的時候,會獲取依賴當(dāng)前Bean的其他Bean的beanName,然后遞歸調(diào)用destroySingleton()方法,保證依賴當(dāng)前Bean的其他Bean先銷毀,在進(jìn)行銷毀時,會先調(diào)用DisposableBean的destroy()方法,然后再去調(diào)用其它的銷毀邏輯,其它的銷毀邏輯基本就是從各種緩存中根據(jù)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依賴了
		// 所以現(xiàn)在要銷毀某個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 {
				//會調(diào)用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);
	}

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

新聞標(biāo)題:Spring之Bean生命周期源碼解析-Bean銷毀-創(chuàng)新互聯(lián)
分享網(wǎng)址:http://muchs.cn/article48/cdohep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、網(wǎng)站設(shè)計、靜態(tài)網(wǎng)站網(wǎng)站策劃、外貿(mào)建站、自適應(yīng)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)