spring中怎么指定一个bean的初始化和销毁方法?一下子都搞懂!
spring中的bean的生命周期可以大致的分为:创建(构造)-->初始化-->销毁。
bean的作用域不同,也会影响上面的过程,具体的:
1、创建(构造)
- 单例:在容器启动时就创建
- 多例:每次在获取时创建
2、初始化
- 两者无区别,都是在bean创建并赋值完毕后调用
3、销毁
- 单例:在容器关闭时销毁
- 多例:在创建这个bean后容器就不再管理它,由用户控制,容器不会调用它的销毁方法
这里面的初始化方法和销毁方法我们都可以自定义指定及实现它们的逻辑,若我们在这个bean初始化或者销毁的时候有特殊的处理,就可以在这个自定义初始化方法和销毁方法中实现。
那有哪些方式来指定某个bean的初始化方法和销毁方法呢?总结起来有3种:
- @Bean(initMethod = "init", destroyMethod = "destroy") 来指定一个bean的初始化及销毁方法
- 分别实现 InitializingBean, DisposableBean 的 afterPropertiesSet() 和 destroy()方法
- 使用JSR250中的两个注解:@PostConstruct 和 @PreDestroy
一、 @Bean(initMethod = "init", destroyMethod = "destroy")
也就是使用 @Bean 注解的 initMethod 和 destroyMethod 来指定这个bean的初始化方法和销毁方法。比如:
public class Person {
public Person() {
Console.log("构造方法!");
}
public void init(){
Console.log("初始化方法!");
}
public void destroy(){
Console.log("销毁方法!");
}
}
@Configuration
public class BeanLifeConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Person getPerson(){
return new Person();
}
}
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanLifeConfig.class);
Console.log("容器创建完成!");
applicationContext.close();
}
构造方法!
初始化方法!
容器创建完成!
销毁方法!
可以看出:
- 可以通过 @Bean(initMethod = "init", destroyMethod = "destroy") 来指定一个bean的初始化及销毁方法
- 可以在指定的初始化及销毁方法中完成我们想要的逻辑
- 这里创建的bean是单实例的,在容器启动时就已经创建并初始化
那你肯定会想:那这个bean的作用域是prototype呢?如下:
public class Person {
public Person() {
Console.log("构造方法!");
}
public void init(){
Console.log("初始化方法!");
}
public void destroy(){
Console.log("销毁方法!");
}
}
@Configuration
public class BeanLifeConfig01 {
@Scope("prototype")
@Bean(initMethod = "init", destroyMethod = "destroy")
public Person getPerson(){
return new Person();
}
}
@Test
public void test1() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanLifeConfig01.class);
Console.log("容器创建完成!");
Object getPerson = applicationContext.getBean("getPerson");
applicationContext.close();
}
容器创建完成!
构造方法!
初始化方法!
可以看出:
- 这里创建的bean是多实例的,在获取的时候才会创建并初始化
- 容器销毁时也没有调用销毁方法
- 当用户getBean获得prototype bean的实例后,IOC容器就不再对当前实例进行管理,而是把管理权交由用户,所以这里容器关闭后,bean的销毁方法并没有执行。
二、分别实现 InitializingBean, DisposableBean 的 afterPropertiesSet() 和 destroy()方法
来说第二种指定初始化方法和销毁方法。
那就是这个bean分别实现 InitializingBean, DisposableBean 的 afterPropertiesSet() 和 destroy()方法。
public class Person implements InitializingBean, DisposableBean {
public Person() {
Console.log("构造方法!");
}
@Override
public void afterPropertiesSet() throws Exception {
Console.log("初始化方法!");
}
@Override
public void destroy(){
Console.log("销毁方法!");
}
}
@Configuration
public class BeanLifeConfig02 {
@Bean
public Person getPerson(){
return new Person();
}
}
@Test
public void test2() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanLifeConfig02.class);
Console.log("容器创建完成!");
applicationContext.close();
}
容器创建完成!
构造方法!
初始化方法!
销毁方法!
三、使用注解:@PostConstruct 和 @PreDestroy
第三种就是使用使用JSR250中的两个注解:@PostConstruct 和 @PreDestroy 。
public class Person {
public Person() {
Console.log("Person的构造方法!");
}
@PostConstruct
public void init(){
Console.log("Person的初始化方法!");
}
@PreDestroy
public void destroy(){
Console.log("Person的销毁方法!");
}
}
@Configuration
public class BeanLifeConfig03 {
@Bean
public Person getPerson(){
return new Person();
}
}
@Test
public void test3() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanLifeConfig03.class);
Console.log("容器创建完成!");
applicationContext.close();
}
Person的构造方法!
Person的初始化方法!
容器创建完成!
Person的销毁方法!
四、初始化方法执行前后也能做些“手脚”
上面说了指定初始化方法的三种方法,这里要说的是在你指定的初始化方法执行前后也可以加上一些逻辑处理。
实现的方式时通过实现 BeanPostProcessor 接口的两个方法:postProcessBeforeInitialization()和 postProcessAfterInitialization()。
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Console.log("postProcessBeforeInitialization 在初始化方法前执行" + beanName + "###" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Console.log("postProcessAfterInitialization 在初始化方法后执行" + beanName + "###" + bean);
return bean;
}
}
@Configuration
public class BeanLifeConfig04 {
@Bean
public Person getPerson(){
return new Person();
}
@Bean
public MyBeanPostProcessor myBeanPostProcessor(){
return new MyBeanPostProcessor();
}
}
@Test
public void test4() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanLifeConfig04.class);
Console.log("容器创建完成!");
applicationContext.close();
}
Person的构造方法!
postProcessBeforeInitialization 在初始化方法前执行getPerson###fengge.config.beanLife.annotation.Person@119cbf96
Person的初始化方法!
postProcessAfterInitialization 在初始化方法后执行getPerson###fengge.config.beanLife.annotation.Person@119cbf96
容器创建完成!
Person的销毁方法!
可以看到,在初始化方法前后分别执行了postProcessBeforeInitialization()和 postProcessAfterInitialization()方法中的逻辑。
五、BeanPostProcessor 在spring中有哪些用处?
在初始化前后加上逻辑有啥好处?实际有很多用处,比如bean在初始化之前是有构造和属性赋值的过程,属性赋值时就用到了BeanPostProcessor;再比如bean的校验;在某个bean中注入容器;@Autowired、@Async、@PostConstruct 和 @PreDestroy等注解都是利用了BeanPostProcessor。