(转载)Spring Bean生命周期,实例化顺序

简介

Spring中Bean容器的生命周期。

首先明确一点,并非Spring容器中所有的Bean都有生命周期行为,只有接受容器管理生命周期的Bean才具有生命周期行为;而单例(Singleton)Bean接受容器管理,非单例(non-singleton)Bean在实例化后,完全交给了客户端代码管理,容器不再跟踪其生命周期,每次客户请求,容器都会创建一个新的实例,所以Spring容易无法知晓Bean何时销毁。
Bean容器的生命周期。其实上图有个节点没有画出,就是在实例化所有Bean之前会执行BeanFactoryPostProcessors

实例化

从图中,我们可以看到实例化Bean的顺序:

  1. 构造函数实例化。
  2. 设置属性值(ioc)。
  3. 如果该Bean实现BeanNameAware接口,调用Bean中的BeanNameAware#setBeanName()
  4. 如果该Bean实现BeanFactoryAware接口,调用Bean中的BeanFactoryAware#setBeanFactory()
  5. 调用BeanPostProcessors#postProcessBeforeInitialization()
  6. 如果该Bean实现InitializingBean接口,调用Bean中的afterPropertiesSet()
  7. 调用Bean中的init-method,通常是在配置Bean的时候指定init-method,例如:<bean class="beanClass" init-method="init"></bean>
  8. 调用BeanPostProcessors#postProcessAfterInitialization()

    销毁

    销毁Bean的顺序:
  9. 在指定方法上加上@PreDestroy注解来制定该方法是在销毁之前调用。
  10. 通过实现DisposableBean接口来定制销毁之前的操作方法。
  11. 通过<bean>元素的destroy-method属性指定销毁之前调用的操作方法。

如果该Bean是单例的,则当容器销毁并且该Bean实现DisposableBean接口的时候,调用destory();如果该Bean是prototype,则将准备好的Bean提交给调用者,后续不再管理该Bean的生命周期。

程序

例1

内容:A类中有B类的引用,A类实例化的时候,B类也实例化好,init-method最后执行。

A类

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
package test;
import org.springframework.beans.factory.InitializingBean;

public class A implements InitializingBean {

private B b;
private String name; // = b.funb();
public void setB(B b) {
System.out.println("A.setB initialed");
this.b = b;
}
public A() {
System.out.println("A initialed");
}
public void init() {
System.out.println("init");
//this.name = b.funb();
}

public void initA() {
System.out.println("initA");
//this.name = b.funb();
}
@Override
public String toString() {
return super.toString() + this.name;
}
public void afterPropertiesSet() throws Exception {
this.name = b.funb();
System.out.println("afterPropertiesSet");
}
}

B类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package test;

public class B {

public B() {
System.out.println("B initialed");
}


public String funb() {
System.out.println("funb");
return "B.funb";
}
}

Spring配置

1
2
<bean id="a" class="test.A" init-method="initA"></bean>
<bean id="b" class="test.B"></bean>

控制台

1
2
3
4
5
6
A initialed
B initialed
A.setB initialed
funb //afterPropertiesSet方法里
afterPropertiesSet
initA

例2

xml配置方式

上面顺序第6和第7条。先执行afterPropertiesSet(),再执行init()

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
package test;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.InitializingBean;

public class AnotherDemoBean implements InitializingBean {

//初始化之后执行
@PostConstruct
public void postConstruct() {
System.out.println("AnotherDemoBean: postConstruct-method");
}

//xml配置里初始化执行
public void init() {
System.out.println("AnotherDemoBean: init-method");
}

//重载InitializingBean的方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("AnotherDemoBean: after properties set!");
}
}

Spring XML配置

1
<bean class="test.AnotherDemoBean" init-method="init"></bean>

控制台

1
2
3
AnotherDemoBean: postConstruct-method
AnotherDemoBean: after properties set!
AnotherDemoBean: init-method

注解方式

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
package test;

import javax.annotation.PostConstruct;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class DemoBean implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean {

@PostConstruct
public void init() {
System.out.println("DemoBean: init-method");
}

public void destroy() throws Exception {
System.out.println("DemoBean: destroy-method!");
}

public void afterPropertiesSet() throws Exception {
System.out.println("DemoBean: after properties set!");
}

public void setBeanName(String name) {
System.out.println("DemoBean: beanName aware, [name=" + name + "]");
}

public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("DemoBean: beanFactory aware, [beanFactory=" + beanFactory.toString() + "]");
}
}

Spring XML

1
<context:component-scan base-package="test"></context:component-scan>

控制台

1
2
3
4
DemoBean: beanName aware, [name=demoBean]
DemoBean: beanFactory aware, [beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26aa4a14: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,demoBean,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,propertyConfigurer,abstractBaseDao,crawlerService,erShouFangService,historyPriceService,crawlerPageDao,erShouFangDao,historyPriceDao,wenZhangDao,zuFangDao,wenZhangService,zuFangService,wubaErShouFangServer,xmfishNewsServer,_4399NewsServer,xmfishESFServer,com.amoyz.util.ContextUtil#0,fcJobTask,wzJobTask,fc_min30_server,fangchanCrawler30min,jobTrigger_FangChan_30min,wz_min5_server,wenzhangCrawler5min,jobTrigger_Wenzhang_5min,scheduler,mongo,org.springframework.beans.factory.config.CustomEditorConfigurer#0,org.springframework.beans.factory.config.CustomEditorConfigurer#1,org.springframework.beans.factory.config.CustomEditorConfigurer#2,mongoDbFactory,mongoTemplate,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy]
DemoBean: init-method
DemoBean: after properties set!

XML中指定Init-method,@PostConstruct注解方法哪个先执行

根据上一个例子结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
AnotherDemoBean: postConstruct-method
AnotherDemoBean: after properties set!
AnotherDemoBean: init-method
```
`PostConstruct`先执行,`Init-method`最后执行,跟踪源码得知这个类`CommonAnnotationBeanPostProcessor`,从命名上,我们就可以得到某些信息——这是一个`BeanPostProcessor`。想到什么?在也谈Spring容器的生命周期中,我们提到过`BeanPostProcessor#postProcessBeforeInitialization`是在Bean生命周期中`afterPropertiesSet`和`init-method`之前执被调用的。再次观察`CommonAnnotationBeanPostProcessor`这个类,它继承自`InitDestroyAnnotationBeanPostProcessor`。`InitDestroyAnnotationBeanPostProcessor`顾名思义,就是在Bean初始化和销毁的时候所作的一个前置/后置处理器。
通过查看`InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization()`
```` java
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Couldn't invoke init method", ex);
}
return bean;
}
`

查看findLifecycleMetadata(),跟踪到buildLifecycleMetadata()

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
private LifecycleMetadata buildLifecycleMetadata(final Class clazz) {  
final LifecycleMetadata newMetadata = new LifecycleMetadata();
final boolean debug = logger.isDebugEnabled();
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
if (initAnnotationType != null) {
if (method.getAnnotation(initAnnotationType) != null) {
newMetadata.addInitMethod(method);
if (debug) {
logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
}
if (destroyAnnotationType != null) {
if (method.getAnnotation(destroyAnnotationType) != null) {
newMetadata.addDestroyMethod(method);
if (debug) {
logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
}
}
});
return newMetadata;
}

在这里会去判断某方法有没有被initAnnotationType/destroyAnnotationType注释,如果有,则把方法添加到init/destroy队列中,后续一一执行。
@PostConstruct注解后的方法在BeanPostProcessor前置处理器中就被执行,所以当然要先于InitializingBeaninit-method执行。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×