Spring销毁Bean流程

Spring获取销毁方法

在Spring创建完成Bean之后,不是立刻就把Bean返回存入单例池中,而是会进行销毁逻辑判断。
这里的销毁逻辑,不是执行销毁方法,而是将销毁方法查找出来,方便后续容器关闭的时候调用Bean的销毁方法。

Spring定义销毁方法

Spring一共有三种方式定义销毁方法。

1、实现DisposableBean接口

@Component
public class UserService implements DisposableBean {

	public void destroy() throws Exception {
		System.out.println("destroy");
	}
}

2、实现AutoCloseable接口

@Component
public class UserService implements AutoCloseable {

	public void close() throws Exception {
		System.out.println("destroy");
	}
}

3、注册销毁方法

@Component
public class SpringBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
		beanDefinition.setDestroyMethodName("(inferred)");
	}

	public void resetBeanDefinition(String beanName) {
		MergedBeanDefinitionPostProcessor.super.resetBeanDefinition(beanName);
	}
}

@Component
public class UserService {

	public void close()  {
		System.out.println("destroy");
	}

	public void shutdown() {
		
	}
}

以上三种方式都可以定义销毁方。

Spring查找销毁逻辑

1、当Bean初始化完成之后,单例Bean会调用AbstractBeanFactory.registerDisposableBeanIfNecessary()方法查找销毁逻辑。

2、需要Spring执行销毁逻辑的只能是单例Bean。

3、调用AbstractBeanFactory.requiresDestruction()方法判断当前Bean是否存在销毁方法。

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

1、DisposableBeanAdapter.hasDestroyMethod(bean, mbd),判断是否有销毁Bean的方法

public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
		if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
			return true;
		}
		return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
	}

1、如果实现了DisposableBean或AutoCloseable接口,直接返回true

2、DisposableBeanAdapter.inferDestroyMethodIfNecessary() 判断BeanDefinition中是否注册了销毁方法。

@Nullable
	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)) {
				// Only perform destroy method inference in case of the bean
				// not explicitly implementing the DisposableBean interface
				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);
	}

此方法会是在Bean初始化前的时候,会调用InitDestroyAnnotationBeanPostProcessor.checkConfigMembers(),将Bean的销毁方法添加到checkedInitMethods集合中缓存起来。

public void checkConfigMembers(RootBeanDefinition beanDefinition) {
			Set checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());
			for (LifecycleElement element : this.initMethods) {
				String methodIdentifier = element.getIdentifier();
				if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
					beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
					checkedInitMethods.add(element);
					if (logger.isTraceEnabled()) {
						logger.trace("Registered init method on class [" + this.targetClass.getName() + "]: " + element);
					}
				}
			}
			Set checkedDestroyMethods = new LinkedHashSet<>(this.destroyMethods.size());
			for (LifecycleElement element : this.destroyMethods) {
				String methodIdentifier = element.getIdentifier();
				if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {
					beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier);
					checkedDestroyMethods.add(element);
					if (logger.isTraceEnabled()) {
						logger.trace("Registered destroy method on class [" + this.targetClass.getName() + "]: " + element);
					}
				}
			}
			this.checkedInitMethods = checkedInitMethods;
			this.checkedDestroyMethods = checkedDestroyMethods;
		}

选择合适的销毁方法

public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
			List postProcessors, @Nullable AccessControlContext acc) {

		Assert.notNull(bean, "Disposable bean must not be null");
		this.bean = bean;
		this.beanName = beanName;
		this.invokeDisposableBean = (bean instanceof DisposableBean &&
				!beanDefinition.isExternallyManagedDestroyMethod(DESTROY_METHOD_NAME));
		this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
		this.acc = acc;

		String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
		if (destroyMethodName != null &&
				!(this.invokeDisposableBean && DESTROY_METHOD_NAME.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);
	}

1、销毁的方法只能有一个
2、销毁的方法中不能有参数。

Spring在关闭容器的时候触发Bean的销毁逻辑

Spring设置执行销毁的两种方式

1、手动调用关闭方法

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Appconfig.class);
applicationContext.close();

2、注册一个钩子,在Spring关闭的时候调用

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Appconfig.class);
applicationContext.registerShutdownHook();

两种方式本质都差不多,最终都是调用AbstractApplicationContext.this.doClose()方法。

Spring关闭容器做了以下事情

1、发布一个容器关闭的事件

this.publishEvent((ApplicationEvent)(new ContextClosedEvent(this)));

2、调用AbstractApplicationContext.destroyBeans()方法销毁缓存的单例Bean

		this.containedBeanMap.clear();
        this.dependentBeanMap.clear();
        this.dependenciesForBeanMap.clear();
        this.clearSingletonCache();

3、调用AbstractApplicationContext.closeBeanFactory()销毁Bean工厂。

在销毁Bean的时候,触发Bean的销毁方法

1、先判断是否有Bean依赖了当前Bean,如果存在,则需要先销毁依赖了当前Bean的对象。
2、删除缓存了当前Bean的集合

rotected void removeSingleton(String beanName) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.remove(beanName);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.remove(beanName);
		}
	}

3、销毁当前Bean。
4、清空集合dependenciesForBeanMap当前Bean依赖了哪些Bean
5、调用删除方法是在DisposableBeanAdapter.destroy()方法中。

public void destroy() {
		if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
		   // 销毁前
			for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
				processor.postProcessBeforeDestruction(this.bean, this.beanName);
			}
		}

	......
					// 销毁Bean
					((DisposableBean) this.bean).destroy();
   .......
   // 调用销毁方法
   invokeCustomDestroyMethod(this.destroyMethod);
   ......
	}

你可能感兴趣的:(Spring源码,spring,java,servlet)