触发bean销毁的几种方式:
- 调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#destroyBean
- 调用org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons
- 调用ApplicationContext中的close方法
Bean销毁阶段会依次执行:
- 轮询beanPostProcessors列表,如果是DestructionAwareBeanPostProcessor这种类型的,会调用其内部的postProcessBeforeDestruction方法。
- 如果bean实现了org.springframework.beans.factory.DisposableBean接口,会调用这个接口中的destroy方法。
- 调用bean自定义的销毁方法。
DestructionAwareBeanPostProcessor接口
看一下源码:
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
/**
* bean销毁前调用的方法
*/
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
/**
* 用来判断bean是否需要触发postProcessBeforeDestruction方法
*/
default boolean requiresDestruction(Object bean) {
return true;
}
}
这个接口有个关键的实现类:
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction方法中会调用bean中所有标注了@PreDestroy的方法。
自定义销毁方法有3种方式:
方式1:xml中指定销毁方法
<bean destroy-method="bean中方法名称"/>
方式2:@Bean中指定销毁方法
@Bean(destroyMethod = "销毁的方法")
方式3:api的方式指定销毁方法
this.beanDefinition.setDestroyMethodName(methodName);
初始化方法最终会赋值给下面这个字段
org.springframework.beans.factory.support.AbstractBeanDefinition#destroyMethodName
下面来看销毁的案例:
public class ServiceA {
public ServiceA() {
System.out.println("create " + this.getClass());
}
}
自定义一个DestructionAwareBeanPostProcessor:
public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
System.out.println("准备销毁bean:" + beanName);
}
}
来个测试类:
@Test
public void test1() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//添加自定义的DestructionAwareBeanPostProcessor
factory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
//向容器中注入3个单例bean
factory.registerBeanDefinition("serviceA1", BeanDefinitionBuilder.genericBeanDefinition(ServiceA.class).getBeanDefinition());
factory.registerBeanDefinition("serviceA2", BeanDefinitionBuilder.genericBeanDefinition(ServiceA.class).getBeanDefinition());
factory.registerBeanDefinition("serviceA3", BeanDefinitionBuilder.genericBeanDefinition(ServiceA.class).getBeanDefinition());
//触发所有单例bean初始化
factory.preInstantiateSingletons(); //@1
System.out.println("销毁serviceA1");
//销毁指定的bean
factory.destroySingleton("serviceA1");//@2
System.out.println("触发所有单例bean的销毁");
factory.destroySingletons();
}
上面使用了2种方式来触发bean的销毁[@1和@2]
运行输出:
create class org.ljgui.spring.demo7.ServiceA
create class org.ljgui.spring.demo7.ServiceA
create class org.ljgui.spring.demo7.ServiceA
销毁serviceA1
准备销毁bean:serviceA1
触发所有单例bean的销毁
准备销毁bean:serviceA3
准备销毁bean:serviceA2
可以看到postProcessBeforeDestruction被调用了3次,依次销毁3个自定义的bean。
案例2:触发@PreDestroy标注的方法被调用。
上面说了这个注解是在CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction中被处理的,所以只需要将这个加入BeanPostProcessor列表就可以了。
再来个类:
public class ServiceB {
public ServiceB() {
System.out.println("create " + this.getClass());
}
@PreDestroy
public void preDestroy() { //@1
System.out.println("preDestroy()");
}
}
@1:标注了@PreDestroy注解
测试用例:
public void test2() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//添加自定义的DestructionAwareBeanPostProcessor
factory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor()); //@1
//将CommonAnnotationBeanPostProcessor加入
factory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor()); //@2
//向容器中注入bean
factory.registerBeanDefinition("serviceB", BeanDefinitionBuilder.genericBeanDefinition(ServiceB.class).getBeanDefinition());
//触发所有单例bean初始化
factory.preInstantiateSingletons();
System.out.println("销毁serviceB");
//销毁指定的bean
factory.destroySingleton("serviceB");
}
@1:放入了一个自定义的DestructionAwareBeanPostProcessor
@2:放入了CommonAnnotationBeanPostProcessor,这个会处理bean中标注@PreDestroy注解的方法
看效果运行输出:
create class org.ljgui.spring.demo7.ServiceB
销毁serviceB
准备销毁bean:serviceB
preDestroy()
案例3:看一下销毁阶段的执行顺序
实际上ApplicationContext内部已经将Spring内部一些常见的必须的BeannPostProcessor自动装配到beanPostProcessors列表中,比如熟悉的下面的几个:
1.org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
用来处理@Resource、@PostConstruct、@PreDestroy的
2.org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
用来处理@Autowired、@Value注解
3.org.springframework.context.support.ApplicationContextAwareProcessor
用来回调Bean实现的各种Aware接口
所以通过ApplicationContext来销毁bean,会触发3种方式的执行。
下面就以AnnotationConfigApplicationContext来演示一下销毁操作。
来一个类:
public class ServiceA implements DisposableBean {
public ServiceA() {
System.out.println("创建ServiceA实例");
}
@PreDestroy
public void preDestroy1() {
System.out.println("preDestroy1()");
}
@PreDestroy
public void preDestroy2() {
System.out.println("preDestroy2()");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean接口中的destroy()");
}
//自定义的销毁方法
public void customDestroyMethod() { //@1
System.out.println("我是自定义的销毁方法:customDestroyMethod()");
}
}
上面的类中有2个方法标注了@PreDestroy, 这个类实现了DisposableBean接口,重写了接口的中的destroy方法。
@1:这个destroyMethod一会通过@Bean注解的方式,将其指定为自定义方法。
来看测试用例:
@Configurable
public class DestroyTest {
@Bean(destroyMethod = "customDestroyMethod") //@1
public ServiceA serviceA() {
return new ServiceA();
}
@Test
public void test1() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(DestroyTest.class);
//启动容器
System.out.println("准备启动容器");
context.refresh();
System.out.println("容器启动完毕");
System.out.println("serviceA:" + context.getBean(ServiceA.class));
//关闭容器
System.out.println("准备关闭容器");
//调用容器的close方法,会触发bean的销毁操作
context.close(); //@2
System.out.println("容器关闭完毕");
}
}
上面这个类标注了@Configuration,表示是一个配置类,内部有个@Bean标注的方法,表示使用这个方法来定义一个bean。
@1:通过destroyMethod属性将customDestroyMethod指定为自定义销毁方法。
@2:关闭容器,触发bean销毁操作。
来运行test1,输出:
准备启动容器
创建ServiceA实例
容器启动完毕
serviceA:org.ljgui.spring.demo8.ServiceA@6ae4d4
准备关闭容器
preDestroy2()
preDestroy1()
DisposableBean接口中的destroy()
我是自定义的销毁方法:customDestroyMethod()
容器关闭完毕
可以看出销毁方法调用的顺序:
- @PreDestroy标注的所有方法
- DisposableBean接口中的destroy()
- 自定义的销毁方法。