十七、从单例缓存中获取Bean

从单例缓存中获取Bean

getBean()的第一个过程,获取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
Object sharedInstance = getSingleton(beanName);

/*
* 如果容器中包含对应的bean则直接返回
* 如果 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,只不过具有一点特殊的功能而已。
*/
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

getSingleton()方法

Spring 对单例模式的 bean 只会创建一次。后续,如果再获取该 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
// DefaultSingletonBeanRegistry.java
//singletonObjects 就是Spring内部用来存放单例Bean的对象池,key为beanName,value为Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

//singletonFactories 单例工厂的缓存,key为beanName,value 为ObjectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

// earlySingletonObjects 是早期单例Bean的缓存池,此时Bean已经被创建(newInstance),但是还没有完成初始化
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

// singletonsCurrentlyInCreation 存放了当前正在创建的bean的BeanName
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));

@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 从单例缓冲中加载 bean,//先从一级缓存拿
//singletonObjects 就是Spring内部用来存放单例Bean的对象池,key为beanName,value为Bean
Object singletonObject = this.singletonObjects.get(beanName);
// 缓存中的 bean 为空,且当前 bean 正在创建,属性还没有DI(依赖注入)
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//从二级缓存中拿
// earlySingletonObjects 是早期单例Bean的缓存池,此时Bean已经被创建(newInstance),但是还没有完成初始化
singletonObject = this.earlySingletonObjects.get(beanName);
//如果还拿不到,并且允许bean提前引用(解决循环依赖)
if (singletonObject == null && allowEarlyReference) {
// 加锁
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (sing也letonObject == null) {
//从三级缓存中拿到对象工厂
//singletonFactories 单例工厂的缓存,key为beanName,value 为ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//从工厂中拿到对象
singletonObject = singletonFactory.getObject();
//升级到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 从 singletonFactories 中移除对应的 ObjectFactory
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}

从缓存中获取单例Bean的流程:

  • 第一步,从singletonObjects中获取Bean对象
  • 第二步,如果获取不到且Bean正在创建中,从earlySingletonObjects获取Bean对象
  • 第三步,如果获取不到且允许提前创建,从singletonFactories获取FactoryBean
  • 第四步,如果不为null,则通过FactoryBean.getObject()获取Bean,然后将其加入到 earlySingletonObjects ,并且从 singletonFactories 删除,两者是互斥的,主要用来解决循环依赖的问题
  • 总结就是:从这三个Map依次去取,取不到就取下一个Map

getObjectForBeanInstance()方法

执行完getSingleton()如果sharedInstance != null然后会执行该方法获取真正的实例Bean,执行该方法是因为:

1
如果 sharedInstance 是普通的单例 bean,该方法会直接返回。但如果sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回即可。毕竟 FactoryBean 的实现类本身也是一种 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
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 判断是否为工厂类引用(name 以 & 开头)
if (BeanFactoryUtils.isFactoryDereference(name)) {
// 如果是 NullBean,则直接返回
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 如果 beanInstance 不是 FactoryBean 类型,则抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {//doGetBean中调用默认为null
mbd.isFactoryBean = true;
}
return beanInstance;
}

if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}

Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 尝试从缓存中加载bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 若 object 依然为空,则可以确认,beanInstance 一定是 FactoryBean 。从而,使用 FactoryBean 获得 Bean 对象
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// containsBeanDefinition 检测 beanDefinitionMap 中也就是在所有已经加载的类中
// 检测是否定义 beanName
if (mbd == null && containsBeanDefinition(beanName)) {
// 将存储 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition,
// 如果指定 BeanName 是子 Bean 的话同时会合并父类的相关属性
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是用户定义的,而不是应用程序本身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 核心处理方法,使用 FactoryBean 获得 Bean 对象
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
getObjectFromFactoryBean()方法

从上面可以看出, getObjectForBeanInstance(Object beanInstance, String name, String beanName,RootBeanDefinition mbd) 方法,分成两种情况:

  • 第一种,当该实例对象为非 FactoryBean 类型直接返回给定的 Bean 实例对象 beanInstance
  • 第二种,当该实例对象为FactoryBean 类型,从 FactoryBean ( beanInstance ) 中,获取 Bean 实例对象,即通过getObjectFromFactoryBean()来获取。
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
//缓存 FactoryBean 创建的单例 Bean 对象的映射
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// <1> 为单例模式且缓存中存在
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// <1.2> 从缓存中获取指定的 factoryBean
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 为空,则从 FactoryBean 中获取对象
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
// <1.3> 需要后续处理
if (shouldPostProcess) {
// 若该 Bean 处于创建中,则返回非处理对象,而不是存储它
if (isSingletonCurrentlyInCreation(beanName)) {
return object;
}
// 单例 Bean 的前置处理
beforeSingletonCreation(beanName);
try {
// 对从 FactoryBean 获取的对象进行后处理
// 生成的对象将暴露给 bean 引用
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
// 单例 Bean 的后置处理
afterSingletonCreation(beanName);
}
}
// <1.4> 添加到 factoryBeanObjectCache 中,进行缓存
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
// 为空,则从 FactoryBean 中获取对象
Object object = doGetObjectFromFactoryBean(factory, beanName);
// 需要后续处理
if (shouldPostProcess) {
try {
// 对从 FactoryBean 获取的对象进行后处理
// 生成的对象将暴露给 bean 引用
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}

主要流程如下:

  • 若为单例且单例 Bean 缓存中存在 beanName ,进行后续处理,否则直接调用doGetObjectFromFactoryBean()从 FactoryBean 中获取 Bean 实例对象。
  • 若为单例且单例 Bean 缓存中存在 beanName ,进行后续处理:第一步,获取锁。其实我们可以发现大量的同步锁,锁住的对象都是 this.singletonObjects,主要是因为在单例模式中必须要保证全局唯一
1
2
3
4
5
6
7
//DefaultSingletonBeanRegistry.java
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

@Override
public final Object getSingletonMutex() {
return this.singletonObjects;
}
  • 第二步,从 factoryBeanObjectCache 缓存中获取实例对象 object 。若 object 为空,则调用 doGetObjectFromFactoryBean() 方法,从 FactoryBean 获取 Bean 实例对象,底层是调用 FactoryBean.getObject() 方法,获取 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
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
// 需要权限验证
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
// <x> 从 FactoryBean 中,获得 Bean 对象
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// <x> 从 FactoryBean 中,获得 Bean 对象
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}

// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
  • 第三步,如果需要后续处理( shouldPostProcess = true ),则进行进一步处理,步骤如下:
    • 若该 Bean 处于创建中(isSingletonCurrentlyInCreation(String beanName) 方法返回 true ),则返回非处理的 Bean 对象,而不是存储它。
    • 调用 beforeSingletonCreation(String beanName) 方法,进行创建之前的处理。默认实现将该 Bean 标志为当前创建的。
    • 调用 postProcessObjectFromFactoryBean(Object object, String beanName) 方法,对从 FactoryBean 获取的 Bean 实例对象进行后置处理。
    • 调用 afterSingletonCreation(String beanName) 方法,进行创建 Bean 之后的处理,默认实现是将该 bean 标记为不在创建中。
  • 第四步,加入到 factoryBeanObjectCache 缓存中。
isSingletonCurrentlyInCreation()方法

该方法是用于检测当前 Bean 是否处于创建之中。

  • beforeSingletonCreation(String beanName) 方法,用于添加标志,当前 bean 正处于创建中
  • afterSingletonCreation(String beanName) 方法,用于移除标记,当前 Bean 不处于创建中。

以上两个方法记录了 Bean 的加载状态,是检测当前 Bean 是否处于创建中的关键之处,对解决 Bean 循环依赖起着关键作用

1
2
3
4
5
6
7
8
// DefaultSingletonBeanRegistry.java
// singletonsCurrentlyInCreation 存放了当前正在创建的bean的BeanName
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));

public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}

该集合的元素是通过beforeSingletonCreation(String beanName) 方法添加的:

1
2
3
4
5
6
7
// DefaultSingletonBeanRegistry.java

protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {// 添加
throw new BeanCurrentlyInCreationException(beanName);// 如果添加失败,则抛出 BeanCurrentlyInCreationException 异常。
}
}

该集合的元素是通过afterSingletonCreation(String beanName) 方法移除的:

1
2
3
4
5
6
7
// DefaultSingletonBeanRegistry.java

protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
postProcessObjectFromFactoryBean()方法

postProcessObjectFromFactoryBean(Object object, String beanName) 方法,对从 FactoryBean 处获取的 Bean 实例对象进行后置处理。其默认实现是直接返回 object 对象,不做任何处理。

1
2
3
4
5
6
7
8
9
// DefaultSingletonBeanRegistry.java

/**
*机翻注释:对从FactoryBean获得的给定对象进行后处理。结果对象将暴露给bean引用。
* 默认实现只是按原样返回给定的对象。子类可以覆盖它,例如,以应用后处理器。
*/
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
return object;
}

方法注释里提到了应用后处理器AbstractAutowireCapableBeanFactory.java

该类就覆盖了上边的方法:

1
2
3
4
5
//AbstractAutowireCapableBeanFactory.java
@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}

尽可能保证所有 bean 初始化后都会调用注册的 BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName) 方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。


十七、从单例缓存中获取Bean
http://www.muzili.ren/2022/06/11/从单例缓存中获取Bean/
作者
jievhaha
发布于
2022年6月11日
许可协议