Spring学习笔记之bean的生命周期

理解spring bean的生命周期对于细粒度的控制bean的创建、使用和销毁具有重要的意义,比如我们想要在一个bean创建之后做些额外的操作,合理的使用spring在生命周期中的调用方法,就可以轻易的完成这个任务,不过,首先,我们要理解bean在整个生命周期调用的方法链,才能正确的完成所需的功能。本文的目的是尝试使用实验的方式探索一个bean的生命周期。

我们首先创建一个bean类,它实现了InitializingBean,DisposableBean接口中的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class Person implements InitializingBean,DisposableBean{
private String name;
public Person(){//无参构造方法
System.out.println("Constructor");
}
public void setName(String name){
this.name=name;//属性注入
System.out.println("Property Setter");
}
@PostConstruct//javax中PostConstruct注解
public void postConstruct(){
System.out.println("PostConstruct");
}
@Override//InitializingBean接口方法
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean: afterPropertiesSet");
}
public void initMethod(){//init-method标签方法
System.out.println("init-method");
}
@PreDestroy//javax中PreDestroy注解
public void preDestroy(){
System.out.println("preDestroy");
}
@Override
public void destroy() throws Exception {//DisposableBean接口方法
System.out.println("DisposableBean: destroy");
}
public void destroyMethod(){//destroy-method标签方法
System.out.println("destroy-method");
}
}

我们在spring配置文件中加载此bean,并且配置了init-method和destroy-method

1
2
3
<bean id="person" class="wenqi.bean.Person" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="wenqi"></property>
</bean>

在我们使用ClassPathXmlApplicationContext加载配置文件后,并在执行后使用close方法关闭ClassPathXmlApplicationContext后,得到如下输出

1
2
3
4
5
6
7
8
9
Constructor
Property Setter
PostConstruct
InitializingBean: afterPropertiesSet
init-method
preDestroy
DisposableBean: destroy
destroy-method

可见,在bean的生命周期里,构造方法首先被执行,然后如果有属性注入,则调用方法进行属性注入,属性注入完成后,PostConstruct注解的方法被执行,然后是InitializingBean的afterPropertiesSet方法被执行,而后,init-method方法的标签被执行,之后,bean就处于可被使用的状态。当调用了ClassPathXmlApplicationContext的close之后,则依次调用PreDestroy注解方法,DisposableBean的destroy方法,destroy-method标签中指定的方法。
总结一下,整个调用过程就是Constructor->Setter->PostConstruct->InitializingBean:AfterPropertiesSet->(init-method)->使用中->(容器关闭)->PreDestroy方法->Disposable:destroy方法->(destroy-method)。
其中PostConstruct,PreDestroy注解方法是javax中注解,可见jdk中的基础注解方法会在spring的方法之前调用,接着是InitializingBean和DisposableBean的方法会在标签方法之前执行。(PostConstruct,PreDestroy需要配置context:annotation-config)
理解了执行顺序,如果我们想在实例化之后进行一些操作,既可以使用PostConstruct注解方法,也可以使用InitializingBean中的方法。

加上BeanPostProcessor

如果我们实现了一个BeanPostProcessor的子类,并且将它注册在spring配置文件中,那么这个接口的postProcessBeforeInitialization和postProcessAfterInitialization方法会在属性注入之后(PostConstruct之后)和PreDestroy之前执行。这个类是全局的,也就是说它会在所有的bean实例化之后和销毁之前执行对应的方法。例如,我们注册了一个自定义的BeanPostProcessor。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("MyBeanPostProcessor: postProcessBeforeInitialization,beanName: "+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("MyBeanPostProcessor: postProcessAfterInitialization,beanName: "+beanName);
return bean;
}
}

注册该BeanPostProcessor,我们再次加载上面的bean,得到的结果是

1
2
3
4
5
6
7
8
9
10
11
Constructor
Property Setter
**MyBeanPostProcessor: postProcessBeforeInitialization,beanName: person**
PostConstruct
InitializingBean: afterPropertiesSet
init-method
**MyBeanPostProcessor: postProcessAfterInitialization,beanName: person**
preDestroy
DisposableBean: destroy
destroy-method

也就是说会在属性注入后和销毁前环绕执行postProcessBeforeInitialization和postProcessAfterInitialization,那么如果有多个BeanPostProcessor,结果会是怎样呢,我们多注册一个MyBeanPostProcessor2,它的处理逻辑是一样的,只不过打印的头信息不同,输出结果编程这样

1
2
3
4
5
6
7
8
9
10
11
12
13
Constructor
Property Setter
**MyBeanPostProcessor: postProcessBeforeInitialization,beanName: person**
**MyBeanPostProcessor2: postProcessBeforeInitialization,beanName: person**
PostConstruct
InitializingBean: afterPropertiesSet
init-method
**MyBeanPostProcessor: postProcessAfterInitialization,beanName: person**
**MyBeanPostProcessor2: postProcessAfterInitialization,beanName: person**
preDestroy
DisposableBean: destroy
destroy-method

结论是依次按照配置文件里的顺序执行postProcessBeforeInitialization然后执行初始化后的方法,接着销毁前按顺序执行postProcessAfterInitialization,接着执行销毁方法。
有多个bean,那么BeanPostProcessor会环绕执行每一个bean。

xxxAware接口注入上下文相关对象

另外,Spring生命周期中还提供了注入上下文相关对象的接口,这种接口一般被命名为xxxAware,它们提供的对应的setter方法,将与上下文相关的信息在属性注入后注入到bean对象中使用,上下文相关的信息如:bean的名字,bean创建工厂,bean的上下文对象,这三个常用的上下文相关对象由BeanNameAware,BeanFactoryAware,ApplicationContextAware来完成,只要bean实现对应的接口方法,那么在属性注入后,spring就会将bean的名字(由id属性定义),创建工厂,上下文对象会分别传入这些方法。其中这三个方法的执行属性一次是setBeanName,setBeanFactory,setApplicationContext。ApplicationContext是基于BeanFactory实现的,提供了比建造工厂更多的功能,如读取xml配置文件,设置监听注册等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public void setBeanName(String s) {
System.out.println("BeanNameAware setBeanName:"+s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware setBeanFactory:"+beanFactory);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("ApplicationContext setApplicationContext:"+applicationContext);
}

添加了这三个接口方法后,我们再执行,得到的结果是

1
2
3
4
5
6
7
8
9
10
11
12
13
Constructor
Property Setter
**BeanNameAware setBeanName:dd**
**BeanFactoryAware setBeanFactory**
**ApplicationContext setApplicationContext**
MyBeanPostProcessor: postProcessBeforeInitialization,beanName: dd
PostConstruct
InitializingBean: afterPropertiesSet
init-method
MyBeanPostProcessor: postProcessAfterInitialization,beanName: dd
preDestroy
DisposableBean: destroy
destroy-method

总结

最后,总结整个spring bean的生命周期,可以将其分为四个大块:构造方法,属性注入,初始化方法,销毁方法。其中,属性注入的顺序是bean属性注入,BeanNameAware注入,BeanFactoryAware注入,ApplicationContextAware注入。初始化方法和销毁方法是一一对应的,如初始化方法的顺序是BeanPostProcessor的postProcessBeforeInitialization,javax注解PostConstruct,InitializingBean的afterPropertiesSet,标签方法init-method。
对应的BeanPostProcessor的postProcessAfterInitialization,javax注解preDestroy,DisposableBean的destroy,标签方法destroy-method。

参考文献

Spring点滴四:Spring Bean生命周期
SpringBean生命周期详解
Spring中的作用

声明

本文首发表于我的博客,欢迎关注!已委托维权骑士为本站的文章进行维权,转载须注明文章出处,作者保留文章所有权。

坚持原创技术分享,您的支持将鼓励我继续创作!