BeanFactory#getBean 方法是 spring 最核心的能力之一, 它是 beanDefinition 转化为一个真实完整的 spring bean 的必经之路; getBean 过程中涉及到依赖注入、后置处理器增强等各种技术细节, 很不容易理解, 需要非常有耐心地研读与揣摩;
getBean 方法调用时机

getBean 方法在 ApplicationContext 初始化完各个 beanDefinition 后调用:1
2
3
4
5
6
7
8ClassPathXmlApplicationContext:
new ClassPathXmlApplicationContext("spring-config.xml")
AbstractApplicationContext:
refresh() -> finishBeanFactoryInitialization(beanFactory)
DefaultListableBeanFactory:
preInstantiateSingletons()
-> foreach beanName in beanDefinitionNames:
-> getBean(beanName)
getBean 方法调用链路
以下是对 spring 源码逻辑的简略表达: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
89AbstractBeanFactory:
getBean(beanName) -> doGetBean(beanName)
/**** 尝试从缓存中获取 ****/
-> sharedInstance = getSingleton(beanName)
-> if (sharedInstance != null): return getObjectForBeanInstance(sharedInstance...)
// 原型模式下的循环依赖检测
-> if (isPrototypeCurrentlyInCreation(beanName)): throw exception
// 若当前 beanFactory 不存在 beanDefinition, 尝试从 parentBeanFactory 中获取
-> if (getParentBeanFactory() != null && !containsBeanDefinition(beanName)): return parentBeanFactory.getBean(beanName)
-> mbd = getMergedLocalBeanDefinition(beanName)
// 优先处理所有配置了 @DependsOn 的 beans
-> foreach depend in mbd.getDependsOn():
-> registerDependentBean(depend, beanName)
// 对每个需要依赖的 bean 递归调用 getBean
-> getBean(depend)
// 处理单例 bean 的分支流程
-> if (mbd.isSingleton()):
DefaultSingletonBeanRegistry:
/**** singletonObjectFactory 用于构造单例对象填充进一级缓存 ****/
-> getSingleton(beanName, singletonObjectFactory: () -> {
-> if (singletonObjects.get(beanName) == null):
-> AbstractAutowireCapableBeanFactory:
-> createBean(beanName, mbd, ...) -> doCreateBean(beanName, mbd, ...)
// 实例化
-> instanceWrapper = createBeanInstance(beanName, mbd, ...) -> instantiateBean(beanName, mbd)
// 执行增强 mergedBeanDefinition 的后置处理器
-> applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)
/**** earlyBeanRefFactory 用于构造对象工厂填充进三级缓存 ****/
-> addSingletonFactory(beanName, earlyBeanRefFactory: () ->
getEarlyBeanReference(beanName, mbd, bean)):
-> if (!singletonObjects.containsKey(beanName))
-> singletonFactories.put(beanName, earlyBeanReferenceFactory)
// 依赖注入
-> populateBean(beanName, mbd, instanceWrapper)
// 回调处理所有的 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
-> getBeanPostProcessorCache().instantiationAware.foreach(bp) {
-> bp.postProcessAfterInstantiation(beanInstance, beanName)
}
// 按 name 做依赖注入
-> if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
-> autowireByName(beanName, mbd, bw, newPvs)
-> unsatisfiedNonSimpleProperties(mbd, beanInstance).foreach(propertyName) {
// 直接调用 BeanFactory#getBean(beanName) 加载依赖 bean
-> bean = getBean(propertyName)
......
}
}
// 按 type 做依赖注入
-> if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
-> autowireByType(beanName, mbd, bw, newPvs)
-> unsatisfiedNonSimpleProperties(mbd, beanInstance).foreach(propertyName) {
// 分析 propertyName 对应的 setter
-> pd = bw.getPropertyDescriptor(propertyName)
-> methodParam = BeanUtils.getWriteMethodParameter(pd)
-> desc = new AutowireByTypeDependencyDescriptor(methodParam, eager)
-> bean = resolveDependency(desc, beanName, autowiredBeanNames, converter)
......
}
}
// 回调处理所有的 InstantiationAwareBeanPostProcessor#postProcessProperties
// 和 InstantiationAwareBeanPostProcessor#postProcessPropertyValues
-> getBeanPostProcessorCache().instantiationAware.foreach(bp) {
-> bp.postProcessProperties(pvs, beanInstance, beanName)
-> filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching)
-> bp.postProcessPropertyValues(pvs, filteredPds, beanInstance, beanName)
}
// 初始化
-> initializeBean(beanName, instanceWrapper.getWrappedInstance(), mbd)
......
})
// 处理原型 bean 的分支流程
-> else if (mbd.isPrototype()):
// 逻辑同 singleton: AbstractAutowireCapableBeanFactory#createBean
-> beanInstance = createBean(beanName, mbd, ...)
// 其他 scope 的处理分支
-> else:
-> scopeName = mbd.getScope()
-> scope = scopes.get(scopeName)
-> beanInstance = scope.get(beanName, () -> {
// 逻辑同 singleton: AbstractAutowireCapableBeanFactory#createBean
return createBean(beanName, mbd, ...)
})
-> return beanInstance
循环依赖的注入问题
为了解决属性注入模式下的循环依赖问题 (构造器注入和原型模式不支持循环依赖), spring 在 DefaultSingletonBeanRegistry 中定义了多重缓存系统:
singletonObjects
: 用于存放完全初始化好的 bean, 从该缓存中取出的 bean 可以直接使用 (一级缓存);earlySingletonObjects
: 缓存提前曝光的早期单例对象 (尚未填充属性), 用于解决循环依赖 (二级缓存);singletonFactories
: 缓存单例对象工厂, 用于解决循环依赖 (三级缓存);singletonsCurrentlyInCreation
: 创建过程中的 bean 临时缓存, bean 创建完成就会被移出;
1 | private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); |
加入缓存的相关逻辑: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/**
* 将构造完成的对象加入一级缓存
*/
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
/**
* 将对象工厂加入三级缓存
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
读取缓存的相关代码逻辑:
- 场景一: 仅根据 beanName, 从一、二、三级缓存逐级获取:
调用点: AbstractBeanFactory#doGetBean 第一个执行的逻辑
1 | // DefaultSingletonBeanRegistry.java |
- 场景二: 根据 beanName 和 ObjectFactory, 当一级缓存不存在, 尝试从 ObjectFactory.getObject() 获取:
调用点: AbstractBeanFactory#doGetBean 对单例 bean 的创建
1 | // DefaultSingletonBeanRegistry.java |
整理一下 spring 三个缓存的 put / remove 时机:
put 时机:
- singletonObjects:
- 当 bean 创建完成, 会向其中添加单例对象;
- earlySingletonObjects:
- 在查询缓存时, 当一、二级缓存都查不到, 仅三级缓存命中时, 会从三级缓存取出对象工厂, 计算出早期对象, 并添加到二级缓存;
- singletonFactories:
- 在 bean 创建过程中, populateBean (依赖注入) 之前会向其中添加单例对象工厂;
remove 时机 (销毁 bean 的场景除外):
- singletonObjects:
- 无
- earlySingletonObjects:
- 当向 singletonObjects 添加对象时, 删除相同 beanName 的早期对象;
- 当向 singletonFactories 添加对象工厂时, 删除相同 beanName 的早期对象;
- singletonFactories:
- 当向 singletonObjects 添加对象时, 删除相同 beanName 的对象工厂;
- 当查询命中三级缓存, 随即删除对象工厂, 并将早期对象转入二级缓存;
我们以一个形象的例子来表达循环依赖注入的详细过程, 假设类 A 依赖 B, 类 B 也依赖 A, spring 加载这两个 bean 的过程如下:
三级缓存的设计精髓
为什么不能仅用第一、二级缓存
根据上一节的具体例子, 我们可能会发现, 要实现循环依赖的注入, 好像并不需要第三级缓存, 如果往极限一些看, 只使用基于早期对象的二级缓存其实也能够解开循环依赖注入的问题; 当然, 引入基于完整单例的一级缓存必然能提升加载性能, 在 spring bean 数量庞大的复杂工程里可以显著提升启动速度, 这也是合理的; 可即便如此, 我们貌似也只需要使用前两级缓存就够了, 那么 spring 为什么需要第三级对象工厂的缓存呢?
这是因为上节的例子比较简单, 如果我们为类 A 增加一个注解 @Transactional:1
2
3
4
5
6
7
8
9
10
11
12
13
public class A {
private B b;
public void method() {......}
}
public class B {
private A a;
}
如上所示, 假如 spring 现在只有 earlySingletonObjects 这个早期对象缓存, 在创建 A 的时候, 缓存中放的是原始 A 对象, 可是什么时候对 A 做事务增强 AOP 代理呢? 本来对象 B 中 期望 A 的引用是个事务增强的代理对象, 但是现在缓存拿到的并不是代理对象;
这就是 singletonFactories 三级缓存的作用, 添加三级缓存的地方有一个扩展点:1
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
针对业务主动定义的 bean (mbd.isSynthetic() 判断是否是内置合成 bean), 如果存在 SmartInstantiationAwareBeanPostProcessor 的实现, 就依次调用其 getEarlyBeanReference 方法对原始 bean 做增强:1
2
3
4
5
6
7
8
9
10
11
12protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
最典型的场景就是自动代理创建器 AbstractAutoProxyCreator, 基于此扩展点实现了 AOP 的逻辑;
为什么不能仅用第一、三级缓存
我们继续举一反三: 由上节可知, 我们确实需要一个 singletonFactories 用于早期对象的自适应生成, 但我们 getSingleton 时, 为什么需要从 singletonFactories 拿出对象再移入 earlySingletonObjects 这个二级缓存呢? 为什么不能从 singletonFactories 算出来直接用?
这是因为上节的例子还是不够复杂, 如果我们为类 B 也增加一个注解 @Async:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class A {
private B b;
public void method() {
b.method();
}
}
public class B {
private A a;
public void method() {......}
}
我们看下上述代码涉及到的两个注解各自的处理时机:
- @Transactional: 注解最终被 AnnotationAwareAspectJAutoProxyCreator 处理;
- @Async: 注解最终被 AsyncAnnotationBeanPostProcessor 处理;
AnnotationAwareAspectJAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor, 所以可以在添加三级缓存的 getEarlyBeanReference 方法中被执行, 但 AsyncAnnotationBeanPostProcessor 却没有 (为什么不能直接用 AnnotationAwareAspectJAutoProxyCreator 处理的原因见 本文章), 它只能在依赖注入结束后的 initializeBean 方法中被执行, 所以说 @Async 增强的对象是不会进入三级缓存的;
所以再回到本节的代码, 按照 spring 的依赖注入顺序, 如果该代码能加载成功, A 中的成员 b 的 method() 方法是不可能具备异步返回能力的, 为了避免非用户预期的逻辑出现, 上述代码在 spring 中会直接加载失败, 因为有如下检测: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 if (earlySingletonExposure) {
// 指定不允许从三级缓存中获取, 如果 earlySingletonReference != null, 意味着二级缓存中有当前 bean 的早期对象,
// 也就意味着有其他 bean 依赖了当前 bean 的早期对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 允许循环依赖, 且当前 bean 被其他 bean 依赖
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 找出所有可能依赖当前 bean 的 beans
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
// 只保留已实际创建的依赖当前 bean 的 beans
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// 如果真的有其他 bean 提前依赖了当前 bean 的早期对象, 抛异常
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
protected boolean removeSingletonIfCreatedForTypeCheckOnly(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
removeSingleton(beanName);
return true;
} else
return false;
}
本文前段内容已经提及, getSingleton(beanName, allowEarlyReference) 方法可以指定是否允许从三级缓存查询, 这看起来让人感到很困惑, 但我们结合一下上述代码的执行时机和二级缓存 earlySingletonObjects 的 put 时机就会发现:
- 上述代码在 createBean 中执行, 此时在一级缓存中一定查不到该 bean, 因为还没创建完成;
- 二级缓存中的对象只可能是某个 bean 需要注入循环依赖时, 从三级缓存查询命中并转移过来的, 别无其他可能;
由这两点可以推导出一个结论: 上述代码中 getSingleton(beanName, false) 只要返回不为空: 一定意味着有其他 bean 依赖了当前 bean 的早期对象, 这就是二级缓存 earlySingletonObjects 存在的意义, 它可以帮助 spring 检测是否有不完整的 bean 被非预期地提前注入;