Spring注解08——如何使用@Bean注解指定初始化和销毁的方法?

该系列文章主要学习 雷丰阳老师的《Spring注解驱动》课程总结。
原课程地址:课程地址

包括了自己阅读其他书籍《Spring揭秘》《Spring Boot 实战》等课程。

该系列文档会不断的完善,欢迎大家留言及提意见。

1. 通过 Bean的 一些属性来控制

在 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();
    }
}

发现我们的初始化方法如期被打印了

bean的初始化和销毁

2. 使用 InitializingBean和DisposableBean 在bean初始化和销毁时加一些东西

InitializingBean 原理是什么

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());
    }

}

DisposableBean 原理

实现org.springframework.beans.factory.DisposableBean接口的bean在销毁前,Spring将会调用DisposableBean接口的destroy()方法。也就是说我们可以实现DisposableBean这个接口来定义咱们这个销毁的逻辑。

基本思路和 InitializingBean 类似

public interface DisposableBean {

	void destroy() throws Exception;

}

在bean生命周期结束前调用destroy() 方法。

3. @PostConstruct注解和@PreDestroy注解

@PostConstruct注解

@PostConstruct注解是Java中的注解,并不是Spring提供的注解。

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

@PostConstruct 注解被用来修饰一个非静态的void()方法。被 @PostConstruct 注解修饰的方法会在服务器加载 Servlet 的时候运行,并且只会被服务器执行一次。

被@PostConstruct注解修饰的方法通常在构造函数之后,init()方法之前执行。

@PreDestroy注解

@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();
    }
}

演示结果如下

初始化和销毁容器

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值