我们的对象在Spring中是用Bean来描述的,创建一个Bean的过程是怎么样的,创建的Bean最后存放在哪里?这篇博客给你答案
前期准备
我们需要有一个Spring的运行环境,先声明一个UserDAO的Bean,再从容器中获取
UserDAO.java1
2
3
4
5
6package com.lnw.dao;
import org.springframework.stereotype.Component;
@Component
public class UserDAO {
}
Spring的配置类AppConfig.java1
2
3
4
5
6
7package com.lnw.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.lnw")
public class AppConfig {
}
启动测试
Boot.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package 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
36protected 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#registerBeanDefinition1
2
3protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public 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#doCreateBean1
2
3
4if (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
12package 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
32protected 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#applyBeanPostProcessorsBeforeInitialization1
2
3
4
5
6
7
8
9
10
11
12
13public 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
10package 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处理Bean1
2
3
4
5
6
7
8
9
10
11
12
13public 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#addSingleton1
2
3
4
5
6
7
8protected 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,并且写一个方法,在该方法上注解@PostContruct1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package 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时执行