容器管理着bean的生命周期,bean的生命周期包含创建—初始化—销毁等一系列过程。
Spring允许我们在Bean 初始化完成后以及销毁前执行特定的操作。基本上有三种可以指定特定操作的方式。
1. initMethod() 与 destroyMethod()
首先声明一个基础的Java类:
public class Car {
private String name;
public Car(String name) {
this.name = name;
System.out.println("Car...Constructor ");
}
public void init(){
System.out.println("car name:"+name);
System.out.println("car ... init ...");
}
public void destory(){
System.out.println("car ... destory ...");
}
// 省略get/set
}
使用XML方式配置Bean的时候,通过 元素的 init-method/destroy-method属性可以指定初始化之后 、销毁之前调用的操作方法。
<bean id="car" class="com.baiding.model.Car" init-method="init" destroy-method="destory">
<property name="name" value="audi"/>
</bean>
不过在使用@Bean注解声明bean的时候,也可以做出上述XML配置相同的功能,基本实例如下:
声明一个Java配置类,在配置类中使用@Bean注解声明一个组件
@Configuration
public class LifecycleConfig {
@Bean(initMethod = "init",destroyMethod = "destory")
public Car car(){
return new Car("audi");
}
}
使用测试类测试一下
public class LifecycleTest {
@Test
void test01(){
ApplicationContext ac = new AnnotationConfigApplicationContext(LifecycleConfig.class);
System.out.println("容器创建完毕...");
}
}
执行这个测试方法。在这个测试方法中,我们只是创建好了容器。
Car...Constructor
car name:audi
car ... init ...
容器创建完毕...
car ... destory ...
@Bean 注解默认创建单实例的bean,对于单实例的bean来说:
当对象创建完成,并完成赋值操作之后,开始调用初始化方法 initMethod()
当容器关闭的时候,执行销毁方法 destoryMethod()
对于多实例的bean来说,每次获取bean时都会创建一个实例,容器不会管理这个bean,也就是说容器关闭的时候不会调用多实例bean的销毁方法(只需将bean的@Scope设置为prototype,可以看出容器关闭的时候并没有调用销毁方法)。
2. InitializingBean 与 DisposableBean
还可以让bean实现InitializingBean 接口 定义自身初始化逻辑,实现DisposableBean接口定义销毁逻辑。
改造一下刚开始的Car类:实现上述两个接口
public class Car implements InitializingBean,DisposableBean{
private String name;
public Car(String name) {
this.name = name;
System.out.println("Car...Constructor ");
}
public void initMethod(){
System.out.println("car name:"+name);
System.out.println("car ... initMothod ...");
}
public void destoryMethod(){
System.out.println("car ... destoryMethod ...");
}
public void destroy() throws Exception {
System.out.println("car ...DisposableBean... destory");
}
public void afterPropertiesSet() throws Exception {
System.out.println("car...InitializingBean...afterPropertiesSet");
}
// 省略get、set
}
配置类和测试类不变,直接看结果:
Car...Constructor
car...InitializingBean...afterPropertiesSet
car name:audi
car ... initMothod ...
容器创建完毕...
car ...DisposableBean... destory
car ... destoryMethod ...
从结果可以看出,通过实现接口定义自身的初始化或者销毁逻辑,同样是在容器创建完成,bean对象构造好同时赋值成功之后,开始执行初始化方法,在容器关闭之后执行销毁逻辑。
3. @PostConstruct 与 @PreDestroy
可以在指定方法上加上@PostConstruct或者@PreDestroy注解,来指定该方法是在bean初始化之后还是在销毁之前就调用。
改造一下刚开始的Car类:加上两个方法,分别加上两个注解。
public class Car implements InitializingBean,DisposableBean{
private String name;
public Car(String name) {
this.name = name;
System.out.println("Car...Constructor ");
}
public void initMethod(){
System.out.println("car name:"+name);
System.out.println("car ... initMothod ...");
}
public void destoryMethod(){
System.out.println("car ... destoryMethod ...");
}
public void destroy() throws Exception {
System.out.println("car ...DisposableBean... destory");
}
public void afterPropertiesSet() throws Exception {
System.out.println("car...InitializingBean...afterPropertiesSet");
}
@PostConstruct
public void postConstruct(){
System.out.println("car...postConstruct");
}
@PreDestroy
public void preDestroy(){
System.out.println("car... preDestroy");
}
// 省略get、set
}
配置类和测试类不变,直接看结果:
Car...Constructor
car...postConstruct
car...InitializingBean...afterPropertiesSet
car name:audi
car ... initMothod ...
容器创建完毕...
car... preDestroy
car ...DisposableBean... destory
car ... destoryMethod ...
可以看出,@PostConstruct 与 @PreDestroy 这两个注解与上述两种方法功能基本相似,只是在他们同时起作用的时候,执行顺序还是有些规律的。
初始化之后执行: @PostConstruct > InitializingBean > init-method
销毁之前执行:@preDestroy > DisposableBean > destoryMethod