该系列文章主要学习 雷丰阳老师的《Spring注解驱动》课程总结。
原课程地址:课程地址包括了自己阅读其他书籍《Spring揭秘》《Spring Boot 实战》等课程。
该系列文档会不断的完善,欢迎大家留言及提意见。
在 Bean 初始化和销毁的时候都存在不同的时机中,可以在该时机加入不同的方法,用来控制 Bean的行为。
如何利用注解在 初始化 和 销毁 的时候调用具体的方法呢?
还是用具体的例子来演示初始化和销毁的过程
定义一个 car 对象, 分别有构造方法、初始化方法、销毁方法
public class Car {
public Car() {
System.out.println("生产car……");
}
public void init() {
System.out.println("在生产car的时候加一些颜色");
}
public void destroy() {
System.out.println("在car销毁的时候加一把火");
}
}
继续通过配置类将 Car 注入到容器中
@Configuration
public class CarConfig {
@Bean
public Car car () {
return new Car();
}
}
如何决定是否调用 init()
和 destroy()
方法呢?
我们稍稍深入了解一下 @Bean
可以发现,该注解提供了很多方法用来控制,是否调用这些方法。
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
/**
* 用于控制 组件的名称
*/
@AliasFor("name")
String[] value() default {};
/**
* 用于控制 组件的名称 和 value作用类似
*/
@AliasFor("value")
String[] name() default {};
/**
* 用于控制注入的类型,是按照type还是名称
*/
Autowire autowire() default Autowire.NO;
/**
* 定义初始化的时候调用的方法
*/
String initMethod() default "";
/**
*
*/
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
知道了这些就好办了,我们可以通过注解来控制
@Configuration
public class CarConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car () {
return new Car();
}
}
用测试方法看看我们的init()
和 destroy()
是否被调用
public class TestMain {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(CarConfig.class);
applicationContext.close();
}
}
发现我们的初始化方法如期被打印了
Spring中提供了一个InitializingBean接口,该接口为bean提供了属性初始化后的处理方法,它只包括afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。InitializingBean接口的源码如下所示。
看着名字取得,完全符合编程命名的规范:根据名字知道方法目的。这个方法一看就是在属性设置之后做的一些事情了
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
一般什么时候使用呢?通常在设置一些常见的属性之后,通过 afterPropertiesSet() 来做一些打印或者其他的操作。
比如如下的例子,我想看 CarConfig 被容器加载之后,car 的一些属性通过日志输出
重新定义car的属性
public class Car {
private Long price;
private String color;
public Car(Long price, String color) {
this.price = price;
this.color = color;
}
public Car() {
System.out.println("生产car……");
}
@Override
public String toString() {
return "Car{" +
"price=" + price +
", color='" + color + '\'' +
'}';
}
}
并且将CarConfig 实现 InitializingBean接口,在将 car 注入到容器之后,打印 car的基本信息
@Configuration
public class CarConfig implements InitializingBean {
@Bean
public Car car () {
return new Car(1000L, "red");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(car().toString());
}
}
实现org.springframework.beans.factory.DisposableBean接口的bean在销毁前,Spring将会调用DisposableBean接口的destroy()方法。也就是说我们可以实现DisposableBean这个接口来定义咱们这个销毁的逻辑。
基本思路和 InitializingBean 类似
public interface DisposableBean {
void destroy() throws Exception;
}
在bean生命周期结束前调用destroy() 方法。
@PostConstruct注解是Java中的注解,并不是Spring提供的注解。
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
@PostConstruct 注解被用来修饰一个非静态的void()方法。被 @PostConstruct 注解修饰的方法会在服务器加载 Servlet 的时候运行,并且只会被服务器执行一次。
被@PostConstruct注解修饰的方法通常在构造函数之后,init()方法之前执行。
@PreDestroy注解同样是Java提供的。
被@PreDestroy注解修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。
被@PreDestroy注解修饰的方法会在destroy()方法之后,Servlet被彻底卸载之前执行。执行顺序如下所示:
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}
还是以car 为例,演示两个注解的作用
public class Car {
private Long price;
private String color;
public Car(Long price, String color) {
this.price = price;
this.color = color;
}
public Car() {
System.out.println("生产car……");
}
@PostConstruct
public void init() {
System.out.println("在生产car的时候加一些颜色");
}
@PreDestroy
public void destroy() {
System.out.println("在car销毁的时候加一把火");
}
@Override
public String toString() {
return "Car{" +
"price=" + price +
", color='" + color + '\'' +
'}';
}
}
并且通过注解的方式将其注入到容器中
@Configuration
public class CarConfig {
@Bean
public Car car () {
return new Car(1000L, "red");
}
}
并且利用测试类来演示方法是否如期被执行
public class TestMain {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(CarConfig.class);
applicationContext.close();
}
}
演示结果如下