spring:bean的銷燬

登記需要執行銷燬方法的bean

bean裝配裏面提過,bean初始化完成之後,會註冊成爲添加到disposableBeans,這個disposableBeans就是在關閉的時候,調用其destroy方法來銷燬bean

AbstractBeanFactory#registerDisposableBeanIfNecessary
重點是requiresDestruction方法,用來判斷是否需要手動調用銷燬方法,進去後發現有2個判斷條件,滿足任意一個即可:

  • 是否有銷燬方法:
    • 通過destroy-method指定的destroy方法
    • 實現了DisposableBean接口
    • 銷燬方法名爲(inferred)情況下, 有close或者shutdown方法
  • 有DestructionAwareBeanPostProcessor實現類,並且DestructionAwareBeanPostProcessor#requiresDestruction判斷滿足條件(可通過實現DestructionAwareBeanPostProcessor接口來擴展)
    • 實現了ApplicationListener
    • scheduledTasks定時任務裏面存在
    • 實現了Servlet
    • 有方法加上了@PreDestroy註解

如果滿足條件,創建DisposableBeanAdapter進行註冊(添加到disposableBeans)

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
	AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
	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, getBeanPostProcessors(), acc));
		}
		...
	}
}

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

第二個判斷條件一下看上去有點看不懂,實際上它是提供一個可擴展的方式來決定是否需要手動執行銷燬動作,我們來看下他目前的實現類,
在這裏插入圖片描述
另外3個都是比較簡單的一個判斷,

我們來主要看下CommonAnnotationBeanPostProcessor,發現他實現了InstantiationAwareBeanPostProcessor接口,對的,就是bean構建過程中會進行調用,下面來看做了啥

首先,初始化的時候,設置了setDestroyAnnotationType(PreDestroy.class)

在對象構建完後,調用其postProcessMergedBeanDefinition方法時,會遍歷對象的方法找出用於銷燬的方法存到destroyMethods(根據setDestroyAnnotationType設置的類型),最後就可以用來判斷該對象是否需要銷燬動作以及具體銷燬的動作的執行

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
		implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
	...
	
	public CommonAnnotationBeanPostProcessor() {
		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
		setInitAnnotationType(PostConstruct.class);
		setDestroyAnnotationType(PreDestroy.class);
		ignoreResourceType("javax.xml.ws.WebServiceContext");
	}

	...
	// 父類方法
	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
		if (beanType != null) {
			InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
			metadata.checkConfigMembers(beanDefinition);
		}
	}
	...
	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;
	}

	// 父類方法
	private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
		final boolean debug = logger.isDebugEnabled();
		LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
		LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
		Class<?> targetClass = clazz;

		do {
			final LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
			final LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();

			ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
				@Override
				public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
					if (initAnnotationType != null) {
						if (method.getAnnotation(initAnnotationType) != null) {
							LifecycleElement element = new LifecycleElement(method);
							currInitMethods.add(element);
							if (debug) {
								logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
							}
						}
					}
					if (destroyAnnotationType != null) {
						if (method.getAnnotation(destroyAnnotationType) != null) {
							currDestroyMethods.add(new LifecycleElement(method));
							if (debug) {
								logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
							}
						}
					}
				}
			});

			initMethods.addAll(0, currInitMethods);
			destroyMethods.addAll(currDestroyMethods);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return new LifecycleMetadata(clazz, initMethods, destroyMethods);
	}
	...
}

註冊關閉鉤子ShutdownHook

之前 JVM關閉 裏面說過,程序正常關閉的時候,JVM會先去調用註冊的關閉鉤子ShutdownHook,spring也是通過這個方式進行銷燬前的動作處理

SpringApplication#createAndRefreshContext
AbstractApplicationContext#registerShutdownHook
在完成上下文創建後,會註冊關閉鉤子

@Override
public void registerShutdownHook() {
	if (this.shutdownHook == null) {
		// No shutdown hook registered yet.
		this.shutdownHook = new Thread() {
			@Override
			public 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.
			// 發佈上下文關閉事件ContextClosedEvent
			publishEvent(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.
		// 銷燬bean
		destroyBeans();

		// Close the state of this context itself.
		closeBeanFactory();

		// Let subclasses do some final clean-up if they wish...
		onClose();

		this.active.set(false);
	}
}

bean銷燬

再來具體看bean銷燬的方法
AbstractApplicationContext#destroyBeans
DefaultListableBeanFactory#destroySingletons
DefaultSingletonBeanRegistry#destroySingletons

流程總結爲:

  1. 取出需要執行銷燬方法的bean(前面註冊登記的)
  2. 遍歷每個bean執行銷燬方法
  3. 取出bean的依賴方,先銷燬依賴方(就是之前bean裝配提到的@DependsOn標誌的依賴方)
  4. 執行bean的destroy方法:
    4.1. 調用DestructionAwareBeanPostProcessor來執行銷燬方法
    4.2. 執行DisposableBean#destroy方法
    4.3. 執行init-method指定的destroy方法
  5. 銷燬內部類對象
  6. 從依賴關係中去掉自己
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 {
			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);
}

DisposableBeanAdapter#destroy

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>() {
					@Override
					public 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);
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章