Spring–bean的生命周期

Spring作为web开发中使用最广泛的框架之一,其本质是一个对象容器,用于帮助开发者管理对象。本文基于Spring5.0.x版本代码,重点讲解Spring中bean的整个生命周期,来方便大家了解Spring的部分设计理念。


1.对象创建

Spring的本质既然是一个对象的容器,那么必然要经过以下步骤创建出对象添加到容器中,这样才能进行管理。

  1. 获取到有哪些对象应该让我去创建
  2. 怎么样去创建

由于本文重点讲解的为对象的生命周期,所以对于扫描对象只是一个最基本的介绍。

1.1 获取到有哪些对象应该让我去创建

使用过Spring的小伙伴应该都知道,对于spring-boot应用会自动扫描其根路径下的所有对象,或者使用@ComponentScan注解和xml配置<context:component-scan/>方式新增扫描basePackages路径,用于让Spring能够感知到我应该去创建哪些对象。

当然Spring提供了远不止这些的途径用于让对象纳入被管理的范围,比如说很多框架常用的ImportBeanDefinitionRegistrar机制,可以实现额外向容器中增加自己的BeanDefinitions。

也正是因为其极高的扩展性,才使得Spring的生态体系越发的庞大。

在Spring中,对象容器可以称为ApplicationContext,ApplicationContext也是个对象,所以他也要进行初始化操作,也就是Spring启动流程,其核心的启动方法如下

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
// 初始化beanFactory,并将bean -> BeanDefinitione
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
// 可以让子类扩展处理BeanFactory,这时候bean还只是BeanDefinitione没有实例化
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
// 执行BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// 开始实例化对象
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

可以看到,其启动流程当中执行很多很多操作,但与我们今天主题有关的操作只有以下几个,所以其他的就直接忽略了,大家看下注释就好

  1. obtainFreshBeanFactory() —获取BeanFactory(也可以理解为初始化BeanFactory,因为一开始BeanFactory还不存在)
  2. finishBeanFactoryInitialization(beanFactory) —真正实例化spring中对象的方法

ApplicationContext在其内部持有了一个BeanFactory对象(其实ApplicationContext也实现了BeanFactory接口),从其名称可以看出,BeanFactory肯定是与对象的创建紧密相关的一个类,先看一下其获取BeanFactory的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 可以理解为初始化操作
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

首先进行了BeanFactory的初始化操作,然后将初始化后的BeanFactory进行返回。

作为工厂,要进行建造,首先要先获取到原材料,那么对象工厂也不例外,肯定要先获取到要创建对象的所有元信息才能进行创建,所以我们可以看一下BeanFactory的初始化代码(代码位于AbstractRefreshableApplicationContext.refreshBeanFactory()中)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 只是创建出BeanFactory,可以理解为先建了一个厂房
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 对beanFactory的一些自定义操作
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

到这里已经看了三段Spring的源代码,不难发现,其方法命名真的很好,并且对于含有复杂操作的方法也都有注释进行描述,很值得我们去学习。

只看方法名就能得到我们要具体关注的内容了,也就是loadBeanDefinitions(beanFactory)这个方法,加载对象描叙,也就是上文提到了,要创建对象,肯定要去获取原材料,在Spring中,BeanDefinition就是生产对象的原材料,所有的对象会先组装为BeanDefinition,储存到beanFactory中,最后在真正的实例化对象是,变成真正的Spring bean。

至于loadBeanDefinitions的具体细节这里就不展开讲了,要详细讲的话不只是我不想写,更有可能的是你不想看。。因为太多了,包含了很多类扫描机制、xml解析的细节,这里只要清楚,经过该步骤,应该被Spring所管理的对象就转变为了BeanDefinition,并存放到了BeanFactory下的beanDefinitionMap中。

注册bean扩展机制之一:一开始也讲过了,在生成BD中,Spring也提供了额外的扩展机制ImportBeanDefinitionRegistrar,实现该接口的registerBeanDefinitions方法,就可以向Spring容器中放入我们自己的对象。

具体的实现机制为Spring中有一个ConfigurationClassPostProcessor的BeanFactoryPostProcessor,在BeanFactory创建的时候会进行回调,这时候,会去扫描当前所有BeanDefinition对象,并去处理@Configuration注解(像@Import、@ImportResource、@Bean都是这时候处理的)。

@Configuration注解描述的类本身会被注册到容器,@Bean描述的方法会被注册到容器,@ImportResource描述的配置文件会被加载会解析出BeanDefinition注册到Spring中

@Import导入的普通类会当做ConfigClass处理,@Import导入的ImportSelector类会执行ImportSelector#selectImports()方法,方法返回的类也作为导入进行处理@Import的逻辑,@Import导入的ImportBeanDefinitionRegistrar类,会调用它的registerBeanDefinitions()方法,由它来自定义注册BeanDefinition的逻辑。

1.2 怎么样去创建

现在,厂房也有了,原材料也有了,那就只剩下要怎么建了。

在finishBeanFactoryInitialization方法中,调用了preInstantiateSingletons方法进行类的初始化操作。对所有beanName进行遍历创建。

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
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Pre-instantiating singletons in " + this);
}

// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
// MergedBD 主要是将合并BD的父类信息到DB中,也就是说该步后RootBeanDefinition包含了父类信息
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 这段是factoryBean相关的代码,如果factoryBean实现了SmartFactoryBean,并且isEagerInit为true,表名要马上开始创建factoryBean实际返回的对象到容器中
if (isFactoryBean(beanName)) {
......
}
else {
getBean(beanName);
}
}
}

// Trigger post-initialization callback for all applicable beans...
// 回调SmartInitializingSingleton接口的afterSingletonsInstantiated方法
......
}

getBean(beanName)方法也就是实际创建bean的方法,以下是createBean方法的部分代码(在Spring中,以do开头命名的方法,往往是具体的执行方法)。

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
48
49
50
51
52
53
54
55
56
57
58
59
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;

// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 根据beanName获取class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}

// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}

try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 回调InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation
// 如果BeanPostProcessors就已经创建了bean则直接返回
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}

try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}

该方法主要是在类实例化前做了一些准备工作,比如解析Class对象类型,修改掉BD中指定要被覆写的方法(这个一般很少会用到,也就是指Spring中的lookup-method和replace-method配置项,可以选择性忽略)。

再往下就是Spring创建对象过程中很让我费劲的一个逻辑,resolveBeforeInstantiation会先去执行postProcessBeforeInstantiation的回调,如果该回调中返回了对象,则不再进行正常的对象创建操作。该步操作一直没太弄明白,这么做的意义是什么,打个问号。

然后就是正常的bean创建方法 ===== doCreateBean方法。

doCreateBean方法负责创建一个对象实例并返回,其具体代码如下。

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {

// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 使用适当的策略创建对象实例,
// 创建策略如下
// 1. factoryBean或者factory method
// 2. 带有注入属性的构造函数
// 3. 无参构造函数
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// autowired等一些postProcessors在这里执行
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}

// 这段是关于解决单例对象循环依赖相关的内容,不在本篇文章范围内
....
....

// Initialize the bean instance.
Object exposedObject = bean;
try {
// 为bean注入属性
populateBean(beanName, mbd, instanceWrapper);
// 执行bean创建相关回调
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}

// 这段是关于解决单例对象循环依赖相关的内容,不在本篇文章范围内
....
....

// Register bean as disposable.
try {
// 注册bean销毁时的回调 例如 实现了DisposableBean接口或者指定了destroy方法
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

return exposedObject;
}

Spring不仅让我们可以往容器中添加bean,同样也提供了很多个扩展点,能让我们在创建bean的各个环节中插入我们的回调函数,包括在对象初始化前、实例化前、初始化后、实例化后、创建成功后、对象销毁等等这些关键环节都有相应扩展机制,在创建对象的方法中,initializeBean方法就负责执行bean创建相关的回调方法。

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
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 实现了xxxAware接口,要注入相应属性
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行BeanPostProcessors的postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
// 先执行InitializingBean的afterPropertiesSet方法 再执行bean指定的init方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 执行BeanPostProcessors的postProcessAfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

到此为止,一个bean对象就算是创建完成了,当然,对于还有很多细节的地方都没详细讲,了解那么透彻,如果不参与Spring相关生态开发的话,意义不是太大,所以接下来总结一下我们在工作中会用的相关内容,也就是Spring bean整个生命周期中相关的回调函数。

从执行顺序上讲有以下几个扩展点可以执行回调

  1. InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation,该方法会在对象实例化前进行回调,在回调时,会回传类的类型和beanName。

  2. InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation,该方法会在对象实例化后进行回调(这个时候属性值还没有进行填充,如果重写了该方法并且返回值为false,那么就不会再进行填充属性的操作了)。

  3. InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues,该方法会在填充bean属性时进行回调,该方法能够对bean的填充属性进行二次修改。

    InstantiationAwareBeanPostProcessor接口相比BeanPostProcessor提供了更细粒度的对象控制,但是,更细的粒度往往意味着要对bean的创建要更为熟悉,否则会造成意想不到的后果。在覆写上面三个方法下要格外小心。

  4. BeanPostProcessor接口的postProcessBeforeInitialization,该方法在每个bean初始化完成前进行回调,BeanPostProcessor针对的是所有bean (有些框架级别的BeanPostProcessor会很早开始执行,但是我们自己创建的一般不在这个范围内)。

  5. InitializingBean接口的afterPropertiesSet,该方法在bean初始化时进行回调。

  6. bean声明的InitMethod,该方法同样在bean初始化时进行回调。

  7. BeanPostProcessor接口的postProcessAfterInitialization,该方法在每个bean初始化后进行回调,可以理解为,这个阶段,bean的初始化工作都已经执行完成了。

  8. SmartInitializingSingleton接口的afterSingletonsInstantiated,该方法在所有非懒加载的单例bean创建完成后进行回调。

  9. DisposableBean接口的destroy方法,该方法在类被销毁时进行调用。

  10. bean声明的destroyMethod

可以看到啊,afterPropertiesSet、InitMethod都是bean的初始化阶段进行回调,俩者的区别,在我看来只是一个要实现接口进行初始化,一个则需要在配置中声明InitMethod,就只是一个用法上的不同,在本质上并没有区别。

还有一条特殊的bean的创建流程,如果postProcessBeforeInstantiation提前返回了对象,那么只执行以下两个回调bean就创建成功了。

  1. InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation

  2. BeanPostProcessor接口的postProcessAfterInitialization