Spring指定初始化方法和销毁方法的三种方式

1,678 阅读4分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

1. @PostConstruct@PreDestroy

@PostConstruct@PreDestroy它是Java自己的注解,是JSR-250规范里面定义的一个注解

image.png

@PostConstruct注解被用来修饰一个非静态的void()方法。被@PostConstruct注解修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。被@PostConstruct注解修饰的方法通常在构造函数之后,init()方法之前执行

在Spring框架中使用到@PostConstruct注解的,该注解的方法在整个bean初始化中的执行顺序如下:

Constructor(构造方法)→ @Autowired(依赖注入)→ @PostConstruct(注释的方法)

@PreDestroy注解同样是Java提供的,它也是JSR-250规范里面定义的一个注解。

@PreDestroy注解修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servletdestroy()方法。被@PreDestroy注解修饰的方法会在destroy()方法之后,Servlet被彻底卸载之前执行。执行顺序如下所示:

destroy()方法→ @PreDestroydestroy()方法 → bean销毁

案例:

import lombok.Data;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/6 22:26
 */
@Data
public class Car {

   private String name;

   public Car() {
      System.out.println("执行了Car()构造方法");
   }

   @PostConstruct
   public void postConstruct() {
      System.out.println("执行了Car#postConstruct初始化方法");
   }

   @PreDestroy
   public void preDestroy() {
      System.out.println("执行了Car#preDestroy销毁方法");
   }

}
import com.example.beans.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Description:
 * 配置类
 *
 * @author jack
 * @date 2021/8/6 22:25
 */
@Configuration
public class MainConfig {

   @Bean
   public Car car() {
      return new Car();
   }

}

启动类

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/6 22:31
 */
public class ApplicationTest {
   public static void main(String[] args) {
      AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
      app.close();
   }
}

运行结果如下:

image.png

2.实现InitializingBeanDisposableBean 接口

InitializingBean接口,该接口为bean提供了属性初始化后的处理方法,它只包括afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。

image.png

DisposableBean接口在bean的生命周期结束前被调用

image.png

DisposableBean接口使用注意事项

多实例bean的生命周期不归Spring容器来管理,这里的DisposableBean接口中的方法是由Spring容器来调用的,所以如果一个多实例bean实现了DisposableBean接口是没有啥意义的,因为相应的方法根本不会被调用,当然了,在XML配置文件中指定了destroy方法,也是没有任何意义的。所以,在多实例bean情况下,Spring是不会自动调用bean的销毁方法的。

单例情况下案例:

import lombok.Data;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/6 22:26
 */
@Data
public class Car implements InitializingBean, DisposableBean {

   private String name;

   public Car() {
      System.out.println("执行了Car()构造方法");
   }

   @PostConstruct
   public void postConstruct() {
      System.out.println("执行了Car#postConstruct初始化方法");
   }

   @PreDestroy
   public void preDestroy() {
      System.out.println("执行了Car#preDestroy销毁方法");
   }

   @Override
   public void afterPropertiesSet() throws Exception {
      System.out.println("执行了Car#afterPropertiesSet初始化方法");
   }

   @Override
   public void destroy() throws Exception {
      System.out.println("执行了Car#destroy销毁方法");
   }
}

测试代码不变,测试结果如下

image.png

初始化执行流程

Constructor(构造方法)→ @Autowired(依赖注入)→ @PostConstruct(注释的方法)-> InitializingBean#afterPropertiesSet(bean属性赋值后初始化方法)

销毁执行流程

@PreDestroy(注释的方法)-> DisposableBean#destroybean实现的方法)

多例情况下案例:

import com.example.beans.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
 * Description:
 * 配置类
 *
 * @author jack
 * @date 2021/8/6 22:25
 */
@Configuration
public class MainConfig {

   @Scope(scopeName = "prototype")
   @Bean
   public Car car() {
      return new Car();
   }

}
import com.example.beans.Car;
import com.example.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/6 22:31
 */
public class ApplicationTest {
   public static void main(String[] args) {
      AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
      Car car = app.getBean(Car.class);
      System.out.println(car);
      app.close();
   }
}

测试结果如下:

image.png

可以看到在容器销毁后并没有调用bean的销毁方法

3.使用@Bean注解的属性设置初始化和销毁方法

import lombok.Data;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/6 22:26
 */
@Data
public class Car implements InitializingBean, DisposableBean {

   private String name;

   public Car() {
      System.out.println("执行了Car()构造方法");
   }

   @PostConstruct
   public void postConstruct() {
      System.out.println("执行了Car#postConstruct初始化方法");
   }

   @PreDestroy
   public void preDestroy() {
      System.out.println("执行了Car#preDestroy销毁方法");
   }

   @Override
   public void afterPropertiesSet() throws Exception {
      System.out.println("执行了Car#afterPropertiesSet初始化方法");
   }

   @Override
   public void destroy() throws Exception {
      System.out.println("执行了Car#destroy销毁方法");
   }

   public void beanInit() {
      System.out.println("执行了Car#beanInit初始化方法");
   }

   public void beanDestroy() {
      System.out.println("执行了Car#beanDestroy销毁方法");
   }

}
import com.example.beans.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Description:
 * 配置类
 *
 * @author jack
 * @date 2021/8/6 22:25
 */
@Configuration
public class MainConfig {

   @Bean(initMethod = "beanInit", destroyMethod = "beanDestroy")
   public Car car() {
      return new Car();
   }

}

测试代码不变,测试结果如下

image.png

总结

初始化执行流程

Constructor(构造方法)→ @Autowired(依赖注入)→ @PostConstruct(注释的方法)-> InitializingBean#afterPropertiesSet(bean属性赋值后初始化方法) -> initMethod()(bean的初始化方法)

销毁执行流程

@PreDestroy(注释的方法)-> DisposableBean#destroybean实现的方法)-> destoryMethod()(bean的销毁方法)

借鉴:liayun.blog.csdn.net/article/det…