重学spring(三) Spring IOC 源码分析--获取单例Bean

简介

上一篇文章演演示了Bean的生命周期,我们从容器中获取bean使用一般是 ctx.getBean("xxx"),但这个这个方法具体做了哪些事情我们并不知道,在这篇文章我将详细分析getBean("xxx")方法实现细节,代码比较长,分析不到位的地方,请见谅。

源码分析

入口getBean(String)源码

ctx.getBean("xxx") 调用了BeanFactory 接口的getBean(String name)方法,这里只分析getBean的主逻辑,其调用的方法放在后面分析。

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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
public Object getBean(String name) throws BeansException {
// getBean 是一个空方法,具体的逻辑都封装到了 doGetBean 方法中
return doGetBean(name, null, null, false);
}

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

// 转换 beanName,不直接使用 name 作为 beanName 有亮点原因:
// 1. name 可能是个别名,则需要转换成具体的实例名
// 2. name 可能由 & 字符开头, 在 bean实例化方式的文章中我们知道,& 开头表明需要获取FactoryBean本身,
// 而非 FactoryBean 创建的 bean 。在 BeanFactory 中, FactoryBean 的实例和其他 bean 存储方式
// 是一致的,即 <beanName,bean> ,beanName 中是没有 & 这个字符的。所以需要将 name 的首字符 & 移除,
// 这样才能用缓存中获取 FacotoryBean 实例本身。

final String beanName = transformedBeanName(name);
Object bean;


// 从缓存中获取单例 bean。Spring 是使用 Map 作为 beanName 和 bean 实例的缓存的,这里可以理解为 k->v ,
// 具体的实现后面分析。

Object sharedInstance = getSingleton(beanName);

// 如果 sharedInstance == null,则说明缓存里没有对应的实例,需要创建。
// BeanFactory不是在一开始就将所有bean实例化好,而是在调用 getBean 获取 bean 时再实例化,即懒加载
// getBean 有很多重载,比如 getBean(String name, Object... args) ,在首次获取某个 bean 时,可传入
// 可传入用于初始化的 bean 的参数数组(args), BeanFactory 会根据这些参数去匹配合适的构造方法构造 bean实例。
// 如果bean 已经创建好,args将不会使用,因为beanFactory不会多次实例化单例bean。

if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
// sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
// bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
// FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

// 如果以上条件不满足,则有可能sharedInstance 为空,这时候beanName对应的bean并未创建,
// 当然也有可能bean在父类容器中已经创建好了,所以需要检查一下父类容器。

else {
// BeanFactory 不缓存 Prototype 类型的 bean,无法处理该类型 bean 的循环依赖问题
// 直接抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}

// 检查父类容器中是否存在bean 定义,存在则直接返回父类中的 bean
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 获取 name 对应的 beanName,如果 name 是以 & 字符开头,则返回 & + beanName
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}

if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}

try {
// 合并父 BeanDefinition 与子 BeanDefinition,后面会单独分析
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

// 检查是否有 dependsOn 依赖,如果有则先初始化所依赖的 bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {

// 检测是否存在 depends-on 循环依赖,若存在则抛异常。比如 A 依赖 B,
// B 又依赖 A,他们的配置如下:
// <bean id="beanA" class="BeanA" depends-on="beanB">
// <bean id="beanB" class="BeanB" depends-on="beanA">
// beanA 要求 beanB 在其之前被创建,但 beanB 又要求 beanA 先于它
// 创建。这个时候形成了循环,对于 depends-on 循环,Spring 会直接
// 抛出异常

if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 注册依赖记录
registerDependentBean(dep, beanName);
try {
// 加载 depends-on 依赖
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}

// 创建 bean 实例
if (mbd.isSingleton()) {

// 与上面一样,也是调用 getSingleton()的重载方法来创建实例,该方法会调用ObjectFactory的getObject来
// 创建bean,创建完成后会放入缓存。后面会详细讲。

sharedInstance = getSingleton(beanName, () -> {
try {
// 创建实例
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
// 如果 bean 是 FactoryBean 类型,则调用工厂方法获取真正的 bean 实例。否则直接返回 bean 实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 创建 prototype 类型的 bean 实例
// 可以看到prototype 的bean 不会被缓存,每次调用会创建一个新的bean。
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 创建其他类型的 bean 实例,
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}

// 检查是否需要类型转化,参数指定来bean classType,则需要转化
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}

以上,getBean() 的主体逻辑分析完了,简单总结一下获取单例bean具体的过程:

  1. 转换beanName
  2. 调用 getSingleton 从缓存中获取bean实例 (可能是工厂bean,需要处理具体的获取具体的bean实例)
  3. 如果实例为空,且args == null,调用 getObjectForBeanInstance ,按 name 返回相应的 bean 实例,
  4. 如果上面条件都不满足(实例不为空或者arg != null)则检查父类容器中是否有对应的bean实例,存在则返回
  5. 若父容器中不存在,则进行下一步,合并bean定义(Beandefinition)
  6. 处理依赖(depends-on)
  7. 调用 getSingleton 创建并缓存bean
  8. 调用 getObjectForBeanInstance 返回具体的bean实例()
  9. 若指定了 bean 类型,则转换成对应的 类型

对应流程图如下:

transformedBeanName() 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
30
31
32
33
34
35
36
37
38
// 转换 beanName
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

// 处理 & 字符
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
// 循环处理 & ,“&&&helloFactory”-> "helloFactory"
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}

// 转换别名
public String canonicalName(String name) {
String canonicalName = name;

String resolvedName;
// 为什么要用循环,有可能存在 别名指向别名的情况
// eg. aliasA -> aliasB -> Hello
do {
resolvedName = (String)this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
} while(resolvedName != null);

return canonicalName;
}

从缓存中获取bean实例 getSingleton()

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
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}


// 参数 allowEarlyReference 表示是否允许其他 bean 引用正在创建中的 bean ,用于处理循环引用的问题
// 如;
// <bean id="hello" class="com.study.ioc.life_cycle.Hello">
// <property name="world" ref="world"/>
// </bean>
// <bean id="world" class="com.study.ioc.life_cycle.World">
// <property name="hello" ref="hello"/>
// </bean>
// bean hello 依赖 world,world 又依赖hello,他们之间形成循环依赖,spring在构建hello时,检测到依赖了
// world,则会去实例化 world ,在实例化 world 时检测到依赖 hello ,此时hello已经在初始化过程中了,先让world
// 引用正在初始化的 hello。 world 初始化完成后,hello就可以引用到 world 实例,完成实例化。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从 singletonObjects 获取实例,singletonObjects 缓存的实例都是实例化好的 bean,可以直接用
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从 earlySingletonObjects 中获取提前曝光的 bean ,用于处理循环引用
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果提前曝光的 bena 为空,且允许提前曝光 bean 实例,则从相应的 ObjectFactory 获取一个原始的 bean (未填充属性)
if (singletonObject == null && allowEarlyReference) {
// 获取相应的工厂类
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 返回原始的bean
singletonObject = singletonFactory.getObject();
// 放入提前曝光的缓存中,其他 bean 依赖时可直接从提前曝光的缓存中获取结果
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}

这里解释一下以上代码中涉及的三个缓存的具体作用,后面还会用到:

缓存 用途
singletonObject 用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用
earlySingletonObjects 用于存放还在初始化中的 bean,用于解决循环依赖
singletonFactories 用于存放 bean 工厂。bean 工厂所产生的 bean 是还未完成初始化的 bean. bean 工厂所生成的对象最终会被缓存到 earlySingletonObjects 中

合并父 BeanDefinition 与子 BeanDefinition getMergedLocalBeanDefinition

从 FactoryBean 中获取 bean 实例

前面步骤走完基本都会走到这个方法,在 bean 的实例化方式章节中有讲 FactoryBean 的用法。这里看相关源码:

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
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

// 如果 name 以 & 开头,判断是不是 FactoryBean
if (BeanFactoryUtils.isFactoryDereference(name)) {
// 如果是空的Bean实例,则直接返回
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 不是 FactoryBean 则抛出以异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}

if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}

// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 非 FactoryBean 直接返回了
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}

Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}


重学spring(三) Spring IOC 源码分析--获取单例Bean
https://www.weypage.com/2020/05/13/Java框架/spring/IOC/获取单例bean源码分析/
作者
weylan
发布于
2020年5月13日
许可协议