使用
xml:destroy-method="destroy"
注解:@PreDestroy指定方法
接口:实现DisposableBean或者AutoClostable接口
销毁的过程是发生在spring.close()时候,只有单例bean才会有销毁过程。
创建过程
bean在生命周期,初始化后,有一步是判断当前bean是不是DisposableBean。具体在初始化完(包括初始化前、初始化、初始化后),之后有一步是注册销毁。
AbstractBeanFactory#registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd);
1、判断必须不是原型。并且(是否实现了DisposableBean接口或者是否实现了AutoClostable接口、或者BeanDefinition是否指定了destroyMethod)
2、如果是单例single模型,将beanName作为key,bean作为value存储到beanDefaultSingletonBeanRegistry.disposableBeans Map中。
这里的value是封装到DisposableBeanAdapter类中,DisposableBeanAdapter是继承DisposableBean接口,DisposableBean接口只有一个destroy方法,在实例化DisposableBeanAdapter时候,会把bean中的销毁方法找出来存到method中,在调DisposableBean#destory时候反射method。
3、如果不是single,是自定义的Scope,会根据ScopeName查找出scope,调用调用Scope#registerDestructionCallback。
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()) {
registerDisposableBean(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
else {
Scope scope = this.scopes.get(mbd.getScope());
scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
}
}
spring关闭过程
1、spring关闭会先发布事件
...
publishEvent(new ContextClosedEvent(this));
...
2、调用lifecycleProcessor.onClose()
3、销毁bean
3.1:循环遍历disposableBeans
? 3.1.1:从单例池中移出
? 3.1.2:从disposableBeans中移除
? 3.1.3:调用bean的销毁方法,DisposableBean#destroy
? 3.1.4:获取谁依赖了这个bean,并将依赖的bean销毁
? 3.1.5:如果这个disposableBean还包含了inner beans,将这些Bean从单例池中移除掉
4、清空manualSingletonNames、allBeanNamesByType、singletonBeanNamesByType。
设计模式
我们发现在销毁的时候调用的DisposableBean#destroy,但是我们创建销毁方法有多种,所以需要一种适配器,来适配各种各样的销毁方法,DisposableBeanAdapter看名字Adapter适配器。
DisposableBeanAdapter是实现了DisposableBean。在实例化的时候会去找销毁方法并将方法存到Method中,target存放到bean属性中。在调用DisposableBean#destory的时候会利用反射destroyMethod.invoke(this.bean, args)调用用户指定的销毁方法。
上边有提到了scope的注册销毁
我找了一个,发现实现实现了registerDestructionCallback的方法好少。
public class ServletContextScope implements Scope, DisposableBean {
private final ServletContext servletContext;
private final Map<String, Runnable> destructionCallbacks = new LinkedHashMap<>();
...
@Override
public void registerDestructionCallback(String name, Runnable callback) {
synchronized (this.destructionCallbacks) {
this.destructionCallbacks.put(name, callback);
}
}
...
/**
* Invoke all registered destruction callbacks.
* To be called on ServletContext shutdown.
* @see org.springframework.web.context.ContextCleanupListener
*/
@Override
public void destroy() {
synchronized (this.destructionCallbacks) {
for (Runnable runnable : this.destructionCallbacks.values()) {
runnable.run();
}
this.destructionCallbacks.clear();
}
}
}
对了DisposableBeanAdapter适配器也是先了runnable接口,run方法里边也是销毁的方法,配合线程使用挺人性化的。
上边代码实现了DisposableBean,当spring容器关闭的时候会调用destry,把所有ServletContextScope作用域的有销毁方法的bean全部执行销毁方法。
有个问题是这个是Scope,他是注册到Scopes Map中的。只有bean的生命周期最后才会检查有没有销毁逻辑然后存放到disposableBeans Map中,它这个scope是什么时候到disposableBeans 中的,看源码没有找到