Spring IOC容器初始化原理分析 (第六节上)

「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

1.前言

本文主要讲Spring IOC容器初始化过程中的 finishBeanFactoryInitialization(beanFactory) 方法,如想看之前的内容可查看 Spring IOC容器初始化原理分析 (第五节)

finishBeanFactoryInitialization(beanFactory) 是在Spring IOC 容器初始化过程中 refresh()中调用的,它的主要作用是实例化所有非懒加载的单实例bean

2.refresh()源码

如果需要复制代码,可前往Spring IOC容器初始化原理分析 (第一节)

refresh.jpg

3.finishBeanFactoryInitialization(beanFactory) 源码

2021-11-13_103149.jpg

3.1 第一步详解

这里先把变量的源码贴一下

图片.png
所以到这里 第一步的作用就很简单明了了,先判断 beanFactory 中 是否包含一个名为 conversionService 的bean 且 它的类型是 ConversionService.class 如果有的话,就把它设置到 beanFactory 的 conversionService属性中去。 ConversionService.class是一个用于系统类型转换的接口,我们可以实现它,自定义一些类型转换方式。

3.2 第二步详解

hasEmbeddedValueResolver 的默认实现如下图
图片.png
图片.png
其实这步的主要作用就是判断 embeddedValueResolvers 中是否有 StringValueResolver 对象,如果没有的话,给它注册一个默认的 StringValueResolver 对象,这里StringValueResolver 的作用主要用用来解析注解中字符串的属性值。

3.3第三步详解

这步的主要作用就是,初始化所有的 LoadTimeWeaverAware ,以便尽早的注册它们的转换器。LoadTimeWeaverAware 的主要作用是 在加载sring bean 织入第三方模块,这和spring aop 相关。这里就先不细讲了,想了解的话大家可以官网扒一扒。

3.4 第四步详解

这步作用比较直接:停止使用临时类加载器进行类型匹配,即把临时类型加载器设为null

3.5 第五步详解

缓存所有的bean定义的元数据,不希望后面还修改,即bean 即将被实例化,不希望它的数据被修改。源码如下:

图片.png

4.preInstantiateSingletons() (第六步)

这步的作用就是实例化所有剩余的 非懒加载的单实例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
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
scss复制代码public void preInstantiateSingletons() throws BeansException {
// 日志记录
if (logger.isTraceEnabled()) {
logger.trace("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.
// 创建this.beanDefinitionNames 的副本用于后续的遍历,以允许 init方法注册新的bean定义
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

//触发所有非懒加载的单例bean的初始化
// 遍历所有的 beanName
for (String beanName : beanNames) {
// 根据beanName获取对应的MergedBeanDefinition 这个方法作用 我在4.1中细讲,大家可以往下看
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 判断当它 非抽象,单例,非懒加载 的时候进入
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 判断是否是FactoryBean 这个方法 4.2 中细讲
if (isFactoryBean(beanName)) {
// 得到对应的bean 这个我们会在4.4中 细讲
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// 当 bean是 FactoryBean 类型时,转换一下它的类型
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
// 它表示,是否立即初始化的标识
boolean isEagerInit;
// 这一部分主要是判断它是否需要立即初始化。
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
// 这个我们在 4.5 中说一下
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}

// Trigger post-initialization callback for all applicable beans...
// 遍历所有的 beanName , 为属于 SmartInitializingSingleton 这种类的bean 执行初始化后回调
// 这里bean 已经实例化完成
for (String beanName : beanNames) {
// 拿到beanName 的bean 实例 这里4.3 中细讲
Object singletonInstance = getSingleton(beanName);
// 判断是否属于 SmartInitializingSingleton
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// 执行 SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
// 实例化后的回调方法,
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}

4.1 getMergedLocalBeanDefinition(beanName) 方法

在讲这个方法前,先简单了解一下 BeanDefintion,Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。 BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息以及bean 的作用域,是否懒加载等 创建这个bean 所需要的所有信息。这里我就简单说一下。

图片.png

  • AbstractBeanDefinition:抽象类,实现了BeanDefinition的部分方法。方便子类继承
  • AnnotatedBeanDefinition:注解类型的 BeanDefinition
  • RootBeanDefinition:父级 BeanDefinition
  • ChildBeanDefinition:子级 BeanDefinition,必须设置 parentName 即父级 BeanDefinition的信息
  • GenericBeanDefinition:一般的 BeanDefinition

mergedBeanDefinitions:hashMap key是beanName,value是 RootBeanDefinition
图片.png
图片.png
这个方法的官方定义是:返回合并的RootBeanDefinition,如果指定的bean对应于子bean定义,则遍历父bean定义。

图片.png
这里先取到 RootBeanDefinition mbd,判断当他,不为空,且不需要重新合并定义的时候直接返回(ps: 这里的stale表示是否需要是否需要重新合并定义)
否则的话调用

图片.png
首先先说一下 getBeanDefinition(beanName) :即根据名称从 beanDefinitionMap 取出对应 BeanDefinition

图片.png
图片.png
接着再来讲getMergedBeanDefinition(beanName, getBeanDefinition(beanName))
图片.png
接着往下追

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
scss复制代码protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
// 首先加把锁 保证在执行这个方法时,别的线程不可以修改mergedBeanDefinitions
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;

// Check with full lock now in order to enforce the same merged instance.
// 判断 containingBd为空时 进入
if (containingBd == null) {
// 从 mergedBeanDefinitions(Map) 中取出 RootBeanDefinition (此时mbd类型是RootBeanDefinition,也可能为null)
mbd = this.mergedBeanDefinitions.get(beanName);
}
// 当 mbd 为null 或者 需要重新合并定义时
if (mbd == null || mbd.stale) {
// 记录mbd 当前的引用信息
previous = mbd;
// 置为null
mbd = null;

//当bd.getParentName() == null时,如果bd 是 RootBeanDefinition,把bd拷贝给 mbd,
// 这里比 mbd = new RootBeanDefinition(bd); 多拷贝了一些属性 代码贴在 下面图1
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
// 当bd.getParentName() != null时,说明它是一个Child BeanDefinition 需要与父节点进行合并
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
// transformedBeanName:返回bean名称,必要时去掉工厂解引用前缀,并将别名解析为规范名称。
String parentBeanName = transformedBeanName(bd.getParentName());
// 如果beanName不等于parentBeanName
if (!beanName.equals(parentBeanName)) {
// 返回给定bean名称的合并的 BeanDefinition,必要时将子BeanDefinition与其BeanDefinition合并。 这里放在 下面图二补充
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
// 否则的话 先取得 当前对象的parentBeanFactory,判断当它属于 ConfigurableBeanFactory
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
// 强转一下 调用 getMergedBeanDefinition 和上面相同 具体解释如下面图二
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
// 否则的话 抛出异常
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
//深层次复制,具体如图一
mbd = new RootBeanDefinition(pbd);
// 属性覆盖,具体看图三,使用原始的bd信息,覆盖父级信息
mbd.overrideFrom(bd);
}

// Set default singleton scope, if not configured before.
//判断 mbd的作用域 如果没有 默认给单例
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}

// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
// 包含在非单例Bean中的Bean本身不能是单例的。
// 让我们在此即时进行更正,因为这可能是外部bean的父子合并的结果,在这种情况下,
// 原始内部bean定义将不会继承合并的外部bean的单例状态。
// 如果有传包含bean定义且包含bean定义不是单例但mbd又是单例
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
//设置mbd的作用域 和 containingBd的作用域 一样
mbd.setScope(containingBd.getScope());
}

// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
//暂时缓存合并bean定义
//稍后它可能仍然可以重新合并,以便拾取元数据变更
if (containingBd == null && isCacheBeanMetadata()) {
// 当containingBd为null 且 this.cacheBeanMetadata == true 把合并后的BeanDefinitions重新放到 this.mergedBeanDefinitions 中去
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
//如果previose 不为null , 把 previous 的部分属性 设置给 mbd ,具体属性看图四
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}

图一(多张):

2021-11-13_155417.jpg

2021-11-13_155640.jpg

2021-11-13_164115.jpg

图二(多张):
图片.png
图片.png
这里实际是通过 得到的 parentBeanName ,先判断当容器中的 beanDefinitionMap不包含它时且
this.parentBeanFactory instanceof ConfigurableBeanFactory 时 在调用本身。否则的话
再走一遍4.1的流程

图三:

2021-11-13_163742.jpg

图四:

图片.png

4.2 isFactoryBean(beanName) 源码如下

图片.png
1.先取得最终的beanName,然后拿着这个名字,调用getSingleton(beanNama,false)方法,返回单例对象。
这里 getSingleton 在 4.3 中有详细讲到

  1. beanInstance 不为null 时直接返回 beanInstance instanceof FactoryBean ,否则的话就说明这个beanName对应的bean还没有实例化,则先判断当容器中的 beanDefinitionMap不包含它时且 this.parentBeanFactory instanceof ConfigurableBeanFactory 时 接着判断。

3.isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName))

图片.png
图片.png
图片.png
图片.png
先取出 mbd的isFactoryBean,当它不是null的时候直接返回,否则调用 predictBeanType

  • predictBeanType:获取 targetType
    • getTargetType: 如果已知,返回此bean定义的目标类型,当根据它的 targetType 返回
      如果targetType 不为null 直接返回,否则的话 判断 this.factoryMethodName 不为空时返回resolveBeanClass(mbd, beanName, typesToMatch),这个方法的主要作用:解析指定bean定义的bean类,将bean类名解析为class引用(如果需要),并将解析后的class存储在bean定义中以供进一步使用。这里就不往下继续讲了

4.3 getSingleton(beanName)

主要作用: 获取该beanName 下注册的单实例对象。
源码如下:
图片.png
图片.png
图片.png
图片.png
图片.png
图片.png
图片.png
this.singletonObjects(一级缓存)是一个Map 缓存了所有实例化好的单例对象,对象名–》对象,从里面拿出这个对象。

  • 如果不为null,则直接返回。
  • 否则判断当前正在创建的bean中是否有它(this.singletonsCurrentlyInCreation 保存当前正在创建的对象的名称,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或者在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)
    • 如果没有直接返回
    • 如果有则从this.earlySingletonObjects(二级缓存,保存提前曝光的单例对象:beanName –>bean实例) 中取出
      • 当 allowEarlyReference=false 直接返回.
      • 否则从 this.singletonFactories (三级缓存,保存的是要被实例化的对象的对象工厂 beanName –> ObjectFactory):取出 ObjectFactory 当它不为空的时候 从这里面取到 singletonObject,顺便把它从 singletonFactories 中移除,把它添加到 earlySingletonObjects 中,最终返回 singletonObject.

这里这种设计思想(三级缓存),实际上帮我们解决,单例模式下setter循环依赖的问题(即通过属性相互依赖的问题,构造器依赖spring解决不了)
例如有两个类,A和B ,A中有个属性是B,B中有个属性是A,spring 在初始的时候,先初始A 对象,当A完成初始化的第一步时(此时构造器放在已经执行完成),spring 会将它放在 singletonFactories 中 (具体的初始化过程下篇再讲),然后准备继续往下执行的时候,A 发现 它依赖B对象,A会从容器中尝试获取B,当A没有获取到的时候,就会转而先去创建B对象,B执行完构造器方法后,接着往下执行,发现自己依赖A。于是尝试获取A,从
一级缓存singletonObjects中获取(没有,因为A还没初始化完全),从二级缓存earlySingletonObjects中获取
(也没有),尝试三级缓存singletonFactories中获取,因为A通过ObjectFactory将自己提前曝光了,所以B可以获取到A(虽然没有初始化完全,但是能获取到),然后B完成自己的初始化过程,然后A接着完成自己的初始化过程

5.小结

本来想一篇弄完的,结果发现东西太多了,下篇文章我在继续补,下篇文章主要讲这个的后续的 4.3 getBean()和后面的方法。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%