1. 简介
Spring管理Bean的声明周期可以实现 InitializingBean 和 DisposableBean 接口。容器会调用前者的 afterPropertiesSet() 和后者的 destroy() 来让 Bean 在初始化和销毁 Bean 时执行某些操作。本篇文章将只介绍Bean的销毁。
回顾Bean销毁
实现接口DisposableBean
@Component
public class BeanLifecycle03 implements DisposableBean {
public void destroy() throws Exception {
System.out.println("DisposableBean destroy...") ;
}
}
当容器销毁时会调用上面的destroy方法。
通过注解@PreDestroy
@PreDestroy
public void destroyProcess() {
System.out.println("des...") ;
}
注:这里的方法名可以随意,同时修饰符也可以是private
同时应用上面2种方式:@PreDestroy优先于Disposablebean执行。
通过注解@Bean配置
// 定义bean
public class BeanLifecycle04 {
public void customDestroy() {
System.out.println("BeanLifecycle04 customDestroy...") ;
}
}
@Bean(destroyMethod = "customDestroy")
BeanLifecycle04 beanLifecycle04() {
return new BeanLifecycle04() ;
}
通过destroyMethod属性指定销毁的回调方法。
接下来将介绍销毁回调的其它应用方式。
2. 高级技能
2.1 @Bean自动应用销毁回调
在通过@Bean定义对象时,该注解有个destroyMethod属性默认值是: (inferred)
如果你不去修改该属性,那么你可以在你定义的bean对象中定义如下2个名称的方法
如果你的方法中有上面2个方法任意一个,那么容器在关闭时也是会调用对应的回调方法的,close优先于shutdown方法。如下示例:
public class CommonService {
public void close() {
System.out.println("CommonService close...") ;
}
public void shutdown() {
System.out.println("CommonService shutdown...") ;
}
}
@Bean
public CommonService commonService() {
return new CommonService() ;
}
如上定义后,容器销毁时自动调用上面的close方法,如果没有close方法则查找shutdown方法。这是Spring的自动推断机制。
2.2 实现AutoCloseable接口
除了上面的方式外,我们还可以让对象实现AutoCloseable接口来执行销毁回调。
public class BeanLifecycle04 implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("BeanLifecycle04 AutoCloseable close...") ;
}
}
@Bean
public BeanLifecycle04 beanLifecycle04() {
return new BeanLifecycle04() ;
}
这种方式也是会自动执行close回调方法。
这种方式还有一个好处是,我们可以直接在类上添加@Component注解,这种方式也可以自动调用close方法。
2.3 方法参数
在特殊的情况(通过配置销毁方法)销毁方法都能接收一个参数,而且参数类型必须是Boolean类型,如下示例:
public class CommonService {
public void close(boolean flag) {
System.out.printf("CommonService close...flag: %s%n", flag) ;
}
}
@Bean(destroyMethod = "close")
public CommonService commonService() {
return new CommonService() ;
}
通过上面的方式你可以接受一个boolean类型的参数,必须是boolean,如果是其它参数将会报异常。注:自动推断机制不支持,反而有了参数后将不会执行
2.4 统一添加推断机制
如果你想对所有的bean或者是某些bean统一配置可进行自动推断机制那么你可以通过如下的方式进行处理
public class ProcessInferredBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
String[] names = registry.getBeanDefinitionNames() ;
for (String name : names) {
BeanDefinition beanDefinition = registry.getBeanDefinition(name) ;
String className = beanDefinition.getBeanClassName() ;
if (Objects.nonNull(className) && className.startsWith("com.pack")) {
// 名称必须是它
beanDefinition.setDestroyMethodName("(inferred)") ;
}
}
}
}
如上这样配置后,只要你的bean对象中存在上面说的方法名,那么容器在关闭时就会调用对应的销毁回调方法。