十九、各scope的Bean创建

各scope的Bean创建

在 Spring 中存在着不同的 scope,默认是 singleton ,还有 prototype、request 等其他的 scope 。

singleton

Spring 的 scope 默认为 singleton :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//AbstractBeanFactory.java

if (mbd.isSingleton()) {// 单例模式
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

如果缓存中不存在bean呢?则需要从头开始加载 Bean ,这个过程由 getSingleton(String beanName, ObjectFactory singletonFactory) 方法来实现。

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
// DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 全局加锁
synchronized (this.singletonObjects) {
// <1> 从缓存中检查一遍
// 因为 singleton 模式其实就是复用已经创建的 bean 所以这步骤必须检查
Object singletonObject = this.singletonObjects.get(beanName);
// 为空,开始加载过程
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// <2> 加载前置处理
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// <3> 初始化 bean
// 这个过程其实是调用 createBean() 方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// <4> 后置处理
afterSingletonCreation(beanName);
}
// <5> 加入缓存中
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}

protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);//添加到单例 bean 的缓存。
this.singletonFactories.remove(beanName);//从单例 bean Factory 的缓存中移除。
this.earlySingletonObjects.remove(beanName);//从预加载单例 bean 的缓存中移除。
this.registeredSingletons.add(beanName);//添加到已经注册的单例缓存。
}
}

这个过程并没有真正创建 Bean 对象,仅仅只是做了一部分准备和预处理步骤。真正获取单例 bean 的方法,其实是由 <3> 处的 singletonFactory.getObject() 这部分代码块来实现,而 singletonFactory 由回调方法产生。

该方法做的准备:

  • <1> 处,再次检查缓存是否已经加载过,如果已经加载了则直接返回,否则开始加载过程。
  • <2> 处,调用 beforeSingletonCreation(String beanName) 方法,记录加载单例 bean 之前的加载状态,即前置处理,标记为正在创建中。在从缓存中获取单例Bean已经介绍。
  • <3> 处,调用参数传递的 ObjectFactory 的 getObject() 方法,实例化 bean 。
  • <4> 处,调用 afterSingletonCreation(String beanName) 方法,进行加载单例后的后置处理,删除标记为正在创建中。
  • <5> 处,调用 addSingleton(String beanName, Object singletonObject) 方法,将结果记录并加入值���存中,同时删除加载 bean 过程中所记录的一些辅助状态。

加载完单例Bean后,调用 getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法,从 bean 实例中获取对象。在从缓存中获取单例Bean已经介绍。

prototype

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//AbstractBeanFactory.java

else if (mbd.isPrototype()) {// 原型模式
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// <1> 加载前置处理
beforePrototypeCreation(beanName);
// <2> 创建 Bean 对象
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// <3> 加载后置处理
afterPrototypeCreation(beanName);
}
// <4> 从 Bean 实例中获取对象
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

原型模式的初始化过程很简单:直接创建一个的 Bean 的实例就可以了。

  • <1> 处,调用 beforePrototypeCreation(String beanName) 方法,记录加载原型模式 bean 之前的加载状态,即前置处理。
  • <2> 处,调用 createBean(String beanName) 方法,创建一个 bean 实例对象。
  • <3> 处,调用 afterSingletonCreation(String beanName) 方法,进行加载原型模式 bean 后的后置处理。
  • <4> 处,加载了单例 bean 后,调用 getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法,从 bean 实例中获取对象。在从缓存中获取单例Bean已经介绍。
beforePrototypeCreation()方法

注册为当前正在创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// AbstractBeanFactory.java

protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
afterPrototypeCreation()方法

标记为不在创建中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// AbstractBeanFactory.java

protected void afterPrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal instanceof String) {
this.prototypesCurrentlyInCreation.remove();
}
else if (curVal instanceof Set) {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.remove(beanName);
if (beanNameSet.isEmpty()) {
this.prototypesCurrentlyInCreation.remove();
}
}
}

其他scope

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
else {// 从指定的 scope 下创建 bean
// 获得 scopeName 对应的 Scope 对象
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
// 从指定的 scope 下创建 bean
Object scopedInstance = scope.get(beanName, () -> {
// 加载前置处理
beforePrototypeCreation(beanName);
try {
// 创建 Bean 对象
return createBean(beanName, mbd, args);
}
finally {
// 加载后缀处理
afterPrototypeCreation(beanName);
}
});
// 从 Bean 实例中获取对象
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}

核心流程和原型模式一样,只不过获取 bean 实例是由 Scope.get(String name, ObjectFactory objectFactory) 方法来实现,处理方式和单例模式一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// SimpleThreadScope.java

private final ThreadLocal<Map<String, Object>> threadScope =
new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope") {
@Override
protected Map<String, Object> initialValue() {
return new HashMap<>();
}
};

@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
// 获取 scope 缓存
Map<String, Object> scope = this.threadScope.get();
Object scopedObject = scope.get(name);
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
// 加入缓存
scope.put(name, scopedObject);
}
return scopedObject;
}

总结

比较重要的两个:

  • createBean(String beanName, RootBeanDefinition mbd, Object[] args) 方法。
  • getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法。在从缓存中获取单例Bean已经介绍。

以上两个方法在单例、原型、其他模式中都有调用。不过在单例和其他模式中,createBean()是以回调方式出现的。

getObjectForBeanInstance()这个方法主要是验证以下我们得到的 bean 的正确性,其实就是检测当前 bean 是否是 FactoryBean 类型的 bean 。

如果是,那么需要调用该 bean 对应的 FactoryBean 实例的 getObject() 方法,作为返回值。

无论是从缓存中获得到的 bean 还是通过不同的 scope 策略加载的 bean 都只是最原始的 bean 状态,并不一定就是我们最终想要的 bean。

举个例子,加入我们需要对工厂 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但是我们真正需要的是工厂 bean 中定义 factory-method 方法中返回的 bean,而 getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法,就是完成这个工作的。


十九、各scope的Bean创建
http://www.muzili.ren/2022/06/11/各scope的Bean创建/
作者
jievhaha
发布于
2022年6月11日
许可协议