Spring-Bean的生命周期

我们的对象在Spring中是用Bean来描述的,创建一个Bean的过程是怎么样的,创建的Bean最后存放在哪里?这篇博客给你答案

前期准备

我们需要有一个Spring的运行环境,先声明一个UserDAO的Bean,再从容器中获取
UserDAO.java

1
2
3
4
5
6
package com.lnw.dao;
import org.springframework.stereotype.Component;
@Component
public class UserDAO {

}

Spring的配置类AppConfig.java

1
2
3
4
5
6
7
package com.lnw.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.lnw")
public class AppConfig {
}

启动测试
Boot.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.lnw.test;
import com.lnw.config.AppConfig;
import com.lnw.dao.UserDAO;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Boot {
private int a = 1;
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
// 把我们的AppConfig类注册到BDM中去
ac.register(AppConfig.class);
// refresh是整个Spring中最核心的代码
ac.refresh();
System.out.println(ac.getBean(UserDAO.class).hashCode());
}
}

这样一来就可从容器中获取UserDAO的Bean并输出hashCode

Bean创建的前身BeanDefinition

上面的三段代码,AppConfig配置类中加了@ComponentScan注解,里面指定的扫描的包路径,所以我们的UserDAO类就会被扫描进去。但是扫描出来的类,放进Spring就会被定义成BeanDefinition
什么是BeanDefinition?
简单的说就是创建Bean的原料。如果把Bean比作一道菜的话,那么BeanDefinition就是做这道菜的所有原料。也就是说,BeanDefinition定义了创建Bean的所有东西,包括类型,参数,作用域等等(下面把BeanDefinition简称为BD)
我们可以看看UserDAO的BeanDefinition是什么内容

接下来我们直接看代码
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan会扫描我们指定包下所有加了注解的类,然后把类封装成BeanDefinition注册到BeanDefinitionMap中(BeanDefinitionMap是一个存放BeanDefinition的Map,它在BeanFactory中,以下简称BDM)

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
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
// 声明一个集合来存储BeanDefinition
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 扫描basePackage路径下的java文件
// 并把它转成BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 解析Scope属性
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
// 如果这个类时AbstractBeanDefinition的子类
// 则为它设置默认属性 比如lazy,init destory
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 检查并处理常用的注解
// 这里的处理是把常用的注解的值设置到AnnotationBeanDefinition当中
// 也就是加了注解的类
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 扫描完以后,注册BeanDefinition
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}

我们来看下registerBeanDefinition方法,里面只是简单的使用一个BDR(注册BD的工具)
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#registerBeanDefinition

1
2
3
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 将BD注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

这个BD注册工具会将BD注册到BDM中,目前这个BDM存储在DefaultListableBeanFactory中,这个类中有一个属性,专门用来存储BD的

1
2
3
4
5
6
7
/**
* 这个Map很重要很重要
* Bean的定义的所有数据都存放在这里,也就是说这个Map中存放生产Bean的原料
* @author SouthLight-Lin
*/
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition方法中的代码很长,但是关键的代码就是把BD添加put进去Map中

1
this.beanDefinitionMap.put(beanName, beanDefinition);

接下来,当Spring需要创建Bean时,就从这个BDM中获取BD原料来创建Bean

Bean的生命周期

上面写了那么多,是为了解释BeanDefinition的作用,接下来完整的还原当我们调用getBean时,Bean的生命周期是怎么样的

1、Spring会将扫描出来的类封装成BeanDefinition,为后面的Bean的创建做准备

这是创建Bean的第一步,上面已经讲过

2、先简单的实例化一个对象

Spring会先从容器中getBean,如果这个Bean不存在,就尝试创建一个Bean出来
Spring会从BeanDefinition中通过反射先new出一个对象,然后再对这个对象进行加工使它成为Bean
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

1
2
3
4
if (instanceWrapper == null) {
// 创建一个对象实例(此时还不是Bean,只是一个普通的对象)
instanceWrapper = createBeanInstance(beanName, mbd, args);
}

3、Spring根据Bean的定义填充所有属性,比如它的属性里面有List,String参数,或者有依赖对象,就进行依赖注入

在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean方法的populateBean方法中

1
2
3
4
5
6
7
8
9
10
11
// Initialize the bean instance.
// 将对象复制给exposedObject,然后下面就对这个对象进行初始化,使它成为Bean
Object exposedObject = bean;
try {
// Bean属性的初始化,包括依赖注入
populateBean(beanName, mbd, instanceWrapper);
// 如果实现了InitializingBean,就执行接口里的afterProperty方法进行初始化
// 还执行了Aware接口
// 还执行了BeanPostProcessor的Bean处理器
exposedObject = initializeBean(beanName, exposedObject, mbd);
}

exposedObject = initializeBean(beanName, exposedObject, mbd);这段代码是下面其他步骤的代码,下面再说

我们可以写一个@Autowired方法注入一个Pear对象来试一下,是不是在populateBean方法里面进行依赖注入

结果

populateBean就是对Bean的参数进行设置,包括依赖注入

4、Bean初始化工作的开始,首先进行Aware接口的执行

xxxAware接口是为了使Bean可以获取Spring内部的资源而出现的,比如你可以通过让Bean实现BeanNameAware将Bean容器中的名称设置给Bean自己知道,或者实现BeanFactoryAware将整个容器设置给Bean
比如上面的UserDAO实现了BeanNameAware接口

1
2
3
4
5
6
7
8
9
10
11
12
package com.lnw.dao;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component;
@Component
public class UserDAO implements BeanNameAware{
public String beanName;
@Override
public void setBeanName(String name) {
beanName = name;
}

}

这样就可以将beanName传进来给Bean使用
在第三步的代码中,initializaBean就包括执行Aware接口
initializaBean方法里面包含Bean的生命周期的四个步骤,分别是Aware接口的执行,BeanPostProcessor的前置处理,初始化方法的执行,BeanPostProcessor的后置处理
先贴上代码,再具体说明
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

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
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接口,执行接口的Set方法
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行BeanPostProcessor的前置处理
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
// 执行Bean的初始化方法,比如实现了InitializingBean
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()) {
// 执行BeanPostProcess的后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

5、BeanPostProcessor的前置处理

什么是BeanPostProcessor?BeanPostProcessor就是处理Bean的一个工具,它能在创建Bean的过程之中,对Bean进行处理。只要实现了BeanPostProcessor方法,实现它的前置处理方法(postProcessBeforeInitialization)和后置处理方法(postProcessAfterInitialization),就能在所有Bean的创建过程中对Bean做一些操作
调用applyBeanPostProcessorsBeforeInitialization方法开始对Bean进行BeanPostProcessor的前置处理
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

1
2
3
4
5
6
7
8
9
10
11
12
13
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 循环执行所有BeanPostProcessor
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

通过循环所有的BeanPostProcessor对Bean进行处理,Spring内置的BeanPostProcessor有

这里只说明了几个BeanPostProcessor的小小的功能…其它的目前还不知道

6、Bean的初始化方法的执行

Bean的初始化方法就是Bean刚生成时执行的方法,可以实现InitializingBean来执行初始化方法
在invokeInitMethods方法中
我们让UserDAO实现InitializingBean接口,看何时调用该方法

1
2
3
4
5
6
7
8
9
10
package com.lnw.dao;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class UserDAO implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("executing InitializingBean's afterPropertiesSet");
}
}

我们在afterPropertiesSet方法打下断掉,看何时调用

7、BeanPostProcessor的后置处理

同第五步差不多,当执行完初始化方法之后,就执行BeanPostProcessor的后置处理postProcessAfterInitialization,也是循环调用所有的BeanPostProcessor处理Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 循环执行所有BeanPostProcessor
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

一张图解释4、5、6、7步骤

8、将创建的Bean放进Spring的IOC容器

Spring调用getBean方法获得Bean,当获取不到时,就尝试进行创建,如果创建成功,就把Bean放进IOC容器,以便下次获取(前提是Bean的Scope为singleton,单例模式)
经过上面的步骤,Bean就算是创建完成了,如果Scope属性为单例模式,那么就把Bean放进IOC容器
看一下程序的调用链

当getBean获取不到Bean时就进行创建,如果是Singleton,最后将Bean添加到IOC容器
添加的代码如下
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton

1
2
3
4
5
6
7
8
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

其实,我们常说的IOC容器,就是singletonObjects,它是一个ConcurrentHashMap

9、最后销毁Bean时,如果Bean实现了DisposableBean,它将调用destroy()方法

初始化Bean方法的两种方法:

1、注解@PostConstruct
2、实现InitializingBean 接口

第一种方法比第二种方法先执行,因为@PostConstruct的实现是CommonAnnotationBeanPostProcessor,它是BeanPostProcessor的实现,是一个Bean的处理器,会先调用postBeanPostProcessorBeforeInitialization的前置方法,然后再调用InitializingBean接口的方法
我们可以写段代码来测试一下,UserDAO实现InitializingBean,并且写一个方法,在该方法上注解@PostContruct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.lnw.dao;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class UserDAO implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("executing InitializingBean's afterPropertiesSet");
}

@PostConstruct
public void initMethod(){
System.out.println("@PostConstruct is executing ");
}
}

我们看运行结果

*注:@PreDestroy这个注解是销毁Bean时执行