IOC 初探


本文是对《Spring IOC 容器源码分析》的总结,我对照这篇文章和 Spring 源码进行学习之后,精要化出一些结论。如果时间紧迫可以参考本篇文章,如果时间充裕,更建议对照那篇文章过一遍源码(那篇文章写于2017年,和最新的源码稍有一点点出入,没关系)。

我之前写过一篇介绍 IOC 概念的文章,现在回看想掐死自己……一副什么都不懂却特别跳的样子,气人。

这里重新简要写一下 IOC 的概念:IOC 是控制反转(Inversion of Control)的缩写,控制指的是“控制对象的获得”,比如当需要一个对象的时候,怎么获得这个对象:

  • 常见的“控制”思路,是什么时候需要对象就什么时候 new 一个出来,对象没有创建就无法继续下去,“new 对象”控制了后续代码
  • “控制反转”的思路,是什么时候需要对象就什么时候向资源池要,因为代码需要,所以才向资源池要对象,后续代码控制了对象的获得。

细品一下“控制对象的获得”这几个字就能理解了,可以简单理解为先后顺序。如果先 new 对象再写后续代码,或者是工厂方法获得对象,等等,都使得获取过程要靠自身实现,代码高耦合不便于维护。所以 IOC 的思想是资源由资源池管理,需要的时候让第三方资源池提供。

在 Spring 中 IOC 向资源池要对象,资源池指的是 beanDefinitionMap,这篇文章要学习的内容,就是 beanDefinitionMap 加载资源的初始化过程,也就是 Bean 读取和装载的过程。

(尽管现在使用 IOC 都是通过注解 @AutoWired,但本文仍以最原始的解析 xml 文件来展开。)


通过 ClassPathXmlApplicationContext,将 xml 文件解析成一个个的 Bean,只需要一行代码:

1
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

这个构造方法实际上是在调用另一个构造方法:

1
2
3
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}

而这个构造方法的代码如下:

1
2
3
4
5
6
7
8
9
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
// 根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
setConfigLocations(configLocations);
// 核心方法
if (refresh) {
refresh();
}
}

创建 ClassPathXmlApplicationContext,主要就是在调用 refresh() 方法,叫 refresh 的原因是它会销毁原来的 ApplicationContext,用以重建。这个方法海纳百川,内容量爆炸,我们只看前三个方法(足够理解 IOC 了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public void refresh() throws BeansException, IllegalStateException {

// 加锁,否则 refresh() 没结束,又来一次 refresh() 就出事了
synchronized (this.startupShutdownMonitor) {

// 准备(包括记录启动时间、设置”已启动“状态,处理配置文件的占位符)
prepareRefresh();

// 创建 Bean 工厂(包括初始化 BeanFactory、加载 Bean、注册 Bean 等)
// 这一步结束时,Bean 实例尚未创建
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);

// ...
}
}

我们今天的重点,是第二个方法创建 BeanFactory(obtainFreshBeanFactory()),这个方法能往里扒快 20 层,主要功能是创建 BeanFactory、从 xml 文件中读取信息并解析成多个 BeanDefinition、把所有 Bean 注册到 beanDefinitionMap 中。

但是我们还是从第一个方法开始。


prepareRefresh()

记录时间、状态、校验数据

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
protected void prepareRefresh() {
// 记录启动时间
this.startupDate = System.currentTimeMillis();
// 设置“已启动”状态(这两个都是 AtomicBoolean 类型)
this.closed.set(false);
this.active.set(true);

// 打日志
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}

// 处理配置文件的占位符(默认空实现,交由子类)
initPropertySources();

// 校验配置文件(比如校验 xml 配置文件)
getEnvironment().validateRequiredProperties();

// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}

过。


obtainFreshBeanFactory()

这个方法会创建 Bean 工厂,注册 Bean,是最为重要的一个方法。

我在看博文和源码时,是边学习边截图代码用 PS 拼图的,本想把这部分代码整理成一张大图,结果里面有二十多个子方法,一层层剥进去十几层,PS 画布长八米多……因此用图片做直观学习是不太现实了。

本方法按顺序依次实现了下面这些内容:

  1. 销毁旧的所有 Bean,关闭旧的 BeanFactory
  2. 创建一个新的 BeanFactory
  3. 经过一系列步骤,读取 xml 配置文件
  4. 解析 Bean 定义,生成一个个的 BeanDefinition 的实例
  5. 根据名字,把所有的 Bean 注册在 beanDefinitionMap 里
  6. 注册事件等后续

按照顺序一点点把代码搬上来。

1. 销毁旧的 Bean 和 BeanFactory

如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory(这里销毁的是当前 ApplicationContext 的旧 BeanFactory ,BeanFactory 是可以多个的)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* AbstractRefreshableApplicationContext.java
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果 ApplicationContext 已经加载过 BeanFactory
if (hasBeanFactory()) {
// 销毁所有 Bean
destroyBeans();
// 关闭 BeanFactory
closeBeanFactory();
}
// ...
}

2. 创建一个新的 BeanFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected final void refreshBeanFactory() throws BeansException {
// ...(销毁旧的 Bean 和 BeanFactory)

try {
// 初始化一个 BeanFactory,默认指定 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 用于 BeanFactory 的序列化
beanFactory.setSerializationId(getId());
// 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
customizeBeanFactory(beanFactory);

// ...
}
catch (IOException ex) {
throw new ...
}
}

创建的新的 BeanFactory 类型是 DefaultListableBeanFactory,createBeanFactory()

1
2
3
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

BeanFactory 的继承关系如图(图片源于学习博文):

BeanFactory

从继承关系可以看到,这个 DefaultListableBeanFactory 是所有 BeanFactory 的集大成者,实现了

  • 可以获取多个 Bean(最顶层 BeanFactory 接口的方法都是获取单个 Bean 的)
  • 可以将各个 BeanFactory 设置为父子关系
  • 可以自动装配 Bean(Autowire)

在创建了一个 BeanFactory 之后,紧接着给它设置了三个属性(代码不贴了):

  • 设置序列化 ID(使用 applicationContext 的 ID)
  • 设置是否允许 BeanDefinition 覆盖
  • 设置是否允许循环引用

BeanDefinition 覆盖的默认配置是:在同一配置文件中 Bean id 或 name 重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖。循环引用的意思是:A 依赖 B,而 B 依赖 A;或 A 依赖 B,B 依赖 C,而 C 依赖 A。

3. 经过一系列步骤,读取 xml 配置文件

这块我都不想贴代码了,一系列步骤的意思就是一系列步骤,往里扒到吐血的那种。

总体上走了这些流程(这些都是指读取 xml 数据):

  1. 创建一个 XmlBeanDefinitionReader 并设置参数,用于读取 xml 数据
  2. 读取 Resource[] 资源数组,遍历逐一处理
  3. 把 Resource 包装成 EncodedResource
  4. 创建一个 Set(ThreadLocal),逐一装入 EncodedResource,检查是否重复加入
  5. 将 EncodedResource 读出 InputStream,再转换成 InputSource
  6. 将 InputSource 转换成 Document(是 w3c 定义的接口,代表着 xml 的节点)
  7. 创建 DocumentReader,用以解析 Document(实际上是解析 Document 中的 Element)。
  8. DocumentReader 内部创建了 BeanDefinitionParserDelegate,用以负责解析 Bean 定义
  9. 解析 Bean 定义(看下一部分),并最终将所有的 Bean (实际上是 BeanDefinition)都装入到 BeanFactory 的 beanDefinitionMap 中,这是一个 ConcurrentHashMap。

4. 解析 Bean 定义

在经过一系列的流程之后,终于将 xml 资源转换成一个个的 Element,这是 w3c 定义的类,在此对应着 xml 文件中的各个节点。

xml 文件中有很多类型的节点,比如 <bean /><import /><alias /> 等。默认的 Element 只有四种:<import /><alias /><bean /><beans />,这是 xmlns="http://www.springframework.org/schema/beans" 定义的,也就是默认的命名空间(default namespace),如果想要解析别的类型,需要增加额外的命名空间。

解析这四种默认的 Element 是采用下面的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
// 处理 <import /> 标签
importBeanDefinitionResource(ele);
} else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
// 处理 <alias /> 标签定义
// <alias name="fromName" alias="toName"/>
processAliasRegistration(ele);
} else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 处理 <bean /> 标签定义,这是我们关注的地方
processBeanDefinition(ele, delegate);
} else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 如果碰到的是嵌套的 <beans /> 标签,需要递归
doRegisterBeanDefinitions(ele);
}
}

我们只关注处理 <bean /> 标签定义,也就是 processBeanDefinition() 方法。

这个方法实际上是把 xml 中的 bean 信息解析成 BeanDefinition,然后再包装成 BeanDefinitionHolder,最终注册到 BeanFactory 中的 beanDefinitionMap 中。

4.5 Bean 是什么

学习到这里要停一下,来探讨一下 Bean 到底是个什么东西。从代码层面上讲,Spring 中的 Bean,可以简单认为是 BeanDefinition 的实例,BeanDefinition 中保存了 Bean 的信息,比如 Bean 指向的是哪个类、是否是单例的、是否懒加载等等。

再梳理一下关系:

  • ApplicationContext 内部持有一个实例化的 BeanFactory(默认是 DefaultListableBeanFactory),以后所有的 BeanFactory 相关的操作其实是委托给这个实例来处理的。

  • BeanFactory 也就是 Bean 容器,它存放着 Spring 中的所有 Bean,存放的方式是用一张 map 存所有的 BeanDefinition(Bean 定义),在 DefaultListableBeanFactory 类中有一个 beanDefinitionMap 变量,就是那张存放所有的 Bean 定义的 map。

    1
    2
    // DefaultListableBeanFactory.java  181行
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
  • 也就是说,解析 xml,实际上就是把 xml 中的所有 Bean 信息都转换成 BeanDefinition 实例,然后存储在 beanDefinitionMap 中。

来看一下 BeanDefinition 接口的定义:

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
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

// 默认只有两种:SINGLETON、PROTOTYPE
// 作用域:单例
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
// 作用域:多例(每次获取 Bean 都会生成一个新的实例)
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

// 据说不重要,略
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;


/* ———————————————— 以下都是一些 get()、set() 方法 ———————————————— */

// 父 Bean(Bean 继承 => 继承父 Bean 的配置信息)
void setParentName(@Nullable String parentName);
String getParentName();

// Bean 的类名称,将来是要通过反射来生成实例的
void setBeanClassName(@Nullable String beanClassName);
String getBeanClassName();

// Bean 的作用域
void setScope(@Nullable String scope);
String getScope();

// Bean 是否懒加载
void setLazyInit(boolean lazyInit);
boolean isLazyInit();

// 该 Bean 依赖的所有的 Bean(不是属性依赖,是 depends-on="" 属性设置的值)
void setDependsOn(@Nullable String... dependsOn);
String[] getDependsOn();

// 是否可以注入到其他类型
// 当注入是根据类型注入时,该设置有效,否则无效,例如根据名称注入无效,都能注入
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();

// 同一个 BeanDefinition 接口的多个实现
// 如果不指定名字的话,Spring 会优先选择设置 primary 为 true 的 bean
void setPrimary(boolean primary);
boolean isPrimary();

// 如果该 Bean 采用工厂方法生成,指定工厂名称
// Bean 可以反射创建,也可以工厂方法创建,这里就是指定工厂
void setFactoryBeanName(@Nullable String factoryBeanName);
String getFactoryBeanName();
// 如果该 Bean 采用工厂方法生成,指定工厂方法名称
void setFactoryMethodName(@Nullable String factoryMethodName);
String getFactoryMethodName();


/* ———————————————— 下面这些懒得写了 ———————————————— */
...
}

4. (继续)解析 Bean 定义

回来,来看通过解析 xml 得到的一个个 Element,是怎么转换成 BeanDefinition 实例的。

上面说到,从 Element 解析成 BeanDefinition 实际上是这个方法:

1
2
3
4
5
// ...
} else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// ...

跟进去看这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 将 <bean /> 节点中的信息提取出来,然后封装到一个 BeanDefinitionHolder 中
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

if (bdHolder != null) {
// 如果有自定义属性的话,进行相应的解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 我们把这步叫做 注册Bean 吧
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 注册完成后,发送事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

这个方法一共做了三件事:

  1. 把 Element 解析成 BeanDefinitionHolder
  2. 把 BeanDefinitionHolder 中的 BeanDefinition 加入到 Bean 容器的 map 中(注册 Bean)
  3. 发送事件

我们先只看第一步,把相关代码贴上来:

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 顺便提下,这里的 Element 是 w3c 定义的,对应一个个 xml 的节点
String id = ele.getAttribute(ID_ATTRIBUTE); // id
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); // name

// 将 name 属性的定义按照 “逗号、分号、空格” 切分,转成 aliases 列表
List<String> aliases = new ArrayList<>();
// StringUtils.hasLength() 是在判断非空
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}

// 如果没有指定 id, 那么用 aliases 列表的第一个名字作为 beanName,并在 aliases 中删掉第一个名字
// 例如 <bean name="m1, m2, m3" class="com.pz.example.MessageServiceImpl" />
// id(beanName):m1 aliases:m2、m3
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}

// 如果解析的是 Bean,不包含子 Bean
// 这里会是 null,然后检查一下 id、aliases、ele 是否是非空,再记录一下新增信息
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}

// 根据 <bean ...>...</bean> 中的配置创建 BeanDefinition,然后把配置中的信息都设置到实例中
// 这行结束后,一个 BeanDefinition 实例就出来了,具体怎么做的跟进去看
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

if (beanDefinition != null) {
// 如果没有 id(beanName),会进入下面这段代码
if (!StringUtils.hasText(beanName)) {
try {
// 没有子 Bean,containingBean 是 null,跳过
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
} else {
// 如果不定义 id 和 name,那么按照刚才的举例
// 1. beanName 为:com.pz.example.MessageServiceImpl#0
// 2. beanClassName 为:com.pz.example.MessageServiceImpl
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
// 把 beanClassName 设置为 Bean 的别名
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
} catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
// 返回 BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}



@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {

this.parseState.push(new BeanEntry(beanName));

// 读取 Bean 的类名和父 Bean
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}

try {
// 根据 className 和 parent 创建 BeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);

// 设置 BeanDefinition 的一堆属性,这些属性定义在 AbstractBeanDefinition 中
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

// 解析 <meta />
parseMetaElements(ele, bd);
// 解析 <lookup-method />
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析 <replaced-method />
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析 <constructor-arg />
parseConstructorArgElements(ele, bd);
// 解析 <property />
parsePropertyElements(ele, bd);
// 解析 <qualifier />
parseQualifierElements(ele, bd);

bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));

return bd;
} catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
} catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
} catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
} finally {
this.parseState.pop();
}

return null;
}

代码很长很繁琐,将 Element 中的信息转换成了 BeanDefinition,其中最重要的是设置 BeanDefinition 的 beanName,也就是 Bean 的 ID。

至此,xml 中的一个节点,就被解析成了一个 BeanDefinition 实例(是一个)。

5. 注册 Bean 到 beanDefinitionMap 里

当获取到一个 BeanDefinition 实例之后,需要把这个实例注册到 Bean 容器里,也就是加入到 BeanFactory 中的 beanDefinitionMap 里。

这一步发生在从 Element 解析到 BeanDefinition 的第二步(往上翻 processBeanDefinition() 方法,没多远),也就是说,注册 Bean 实际上是在解析 xml 时一并完成的,刚获取到一个 BeanDefinition 实例,就直接把这个实例加入到 beanDefinitionMap 里。

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {

// 注册 Bean
String beanName = definitionHolder.getBeanName();
// 往后看
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

// 如果还有别名的话,也要根据别名全部注册一遍,不然根据别名就会找不到 Bean 了
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
// alias -> beanName 保存它们的别名信息,这个很简单,用一个 map 保存一下就可以了,
// 获取的时候,会先将 alias 转换为 beanName,然后再查找
registry.registerAlias(beanName, alias);
}
}
}


@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 校验
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}

// 所有的 Bean 注册之后都会放在 beanDefinitionMap 里(这是个 ConcurrentHashMap)
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 处理重复名称的 Bean 定义的情况(说的是 Bean 循环引用覆盖)
if (existingDefinition != null) {
// 如果不允许重复,抛异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
// 下面分情况打日志,表明在不同情形下发生了 Bean 覆盖
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
} else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
} else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
// Bean 覆盖
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
// 判断是否已经有其他的 Bean 开始初始化了.
// 注意,"注册Bean" 这个动作结束,Bean 依然还没有初始化
// 在 Spring 容器启动的最后,会 预初始化 所有的 singleton beans
if (hasBeanCreationStarted()) {
// 为了迭代器正常,这里需要加锁锁住 beanDefinitionMap
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
} else {
// 最正常的应该是进到这个分支
// 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
this.beanDefinitionNames.add(beanName);
// 这是在处理手动注册的 singleton bean(我们一路走来并没有碰过)
// 如 "environment"、"systemProperties" 等 bean,我们自己也可以在运行时注册 Bean 到容器中的
removeManualSingletonName(beanName);
}
// 这个不重要,在预初始化的时候会用到,不必管它
this.frozenBeanDefinitionNames = null;
}

if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
} else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}

prepareBeanFactory(beanFactory)

看不太明白,抄一下代码和注释吧。

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
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置 BeanFactory 的类加载器,我们知道 BeanFactory 需要加载类,也就需要类加载器,
// 这里设置为加载当前 ApplicationContext 类的类加载器
beanFactory.setBeanClassLoader(getClassLoader());

// 设置 BeanExpressionResolver
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

// 设置 PropertyEditorRegistrar
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

// 添加一个 BeanPostProcessor,这个 processor 比较简单:
// 实现了 Aware 接口的 beans 在初始化的时候,这个 processor 负责回调,
// 这个我们很常用,如我们会为了获取 ApplicationContext 而 implement ApplicationContextAware
// 注意:它不仅仅回调 ApplicationContextAware,还会负责回调 EnvironmentAware、ResourceLoaderAware 等,看下源码就清楚了
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

// 下面几行的意思就是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们,
// Spring 会通过其他方式来处理这些依赖
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

/**
* 下面几行就是为特殊的几个 bean 赋值,如果有 bean 依赖了以下几个,会注入这边相应的值,
* 之前我们说过,"当前 ApplicationContext 持有一个 BeanFactory",这里解释了第一行。
* ApplicationContext 还继承了 ResourceLoader、ApplicationEventPublisher、MessageSource
* 所以对于这几个依赖,可以赋值为 this,注意 this 是一个 ApplicationContext
* 那这里怎么没看到为 MessageSource 赋值呢?那是因为 MessageSource 被注册成为了一个普通的 bean
*/
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

// 这个 BeanPostProcessor 也很简单,在 bean 实例化后,如果是 ApplicationListener 的子类,
// 那么将其添加到 listener 列表中,可以理解成:注册 事件监听器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// 这里涉及到特殊的 bean,名为:loadTimeWeaver,这不是我们的重点,忽略它
// tips: ltw 是 AspectJ 的概念,指的是在运行期进行织入,这个和 Spring AOP 不一样
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

/**
* 从下面几行代码我们可以知道,Spring 往往很 "智能" 就是因为它会帮我们默认注册一些有用的 bean,
* 我们也可以选择覆盖
*/

// 如果没有定义 "environment" 这个 bean,那么 Spring 会 "手动" 注册一个
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// 如果没有定义 "systemProperties" 这个 bean,那么 Spring 会 "手动" 注册一个
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// 如果没有定义 "systemEnvironment" 这个 bean,那么 Spring 会 "手动" 注册一个
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}

到此为止,我们看完了 refresh() 的三个方法,Spring 已经解析并注册了所有 Bean,设置好了 BeanFactory,但是还没有真正实例化 Bean,创建 Bean 实例在 finishBeanFactoryInitialization() 方法中完成,本篇就先不继续学习了,到此为止。