Spring三级缓存解决循环依赖
问题
- 什么是循环依赖?
- Spring 如何解决循环依赖?
- 什么是三级缓存?
- 如何用二级缓存解决循环依赖?
- 如何用三级缓存解决循环依赖?
- 三级缓存解决循环依赖的源码?
# Spring 循环依赖解决三级缓存
# 1. 循环依赖
什么是循环依赖?
// A 依赖于 B
public class A {
@Autowird
private B b;
}
// B 依赖于 A
public class B {
@Autowird
private A a;
}
2
3
4
5
6
7
8
9
10
Circular dependencies
If you use predominantly constructor injection, it is possible to create an unresolvable circular dependency scenario.
For example: Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws a
BeanCurrentlyInCreationException
.One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.
Unlike the typical case (with no circular dependencies), a circular dependency between bean A and bean B forces one of the beans to be injected into the other prior to being fully initialized itself (a classic chicken-and-egg scenario).
依赖的注入方式
- 构造方法注入(无法解决循环依赖)
- Set注入(能够解决循环依赖)
默认的单例(singleton)的场景支持循环依赖;原型(Prototype)的场景不支持循环依赖,会报错。
# 2. 前置知识
暂时先简单描述一下,之后再好好研究并完善。
需要了解 Bean 的创建流程:
- 推断选择构造器
- 实例化对象
- 填充属性,也就是依赖注入
- 初始化前(如,执行带有 @PostConstruct 注解的方法)
- 初始化(如,处理 InitializingBean 接口)
- 初始化后(AOP 增强)
- 代理对象放入单例池
需要区分实例化和初始化的区别:
实例化:通过构造器得到一个对象,里面的属性值为 null
初始化:对已经实例化的对象,执行初始化方法(自定义的方法)
# 3. 三级缓存解决循环依赖
# 3.1 三级缓存
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 一级缓存,单例池
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存
...
}
2
3
4
5
6
7
8
9
10
11
12
⭐ 第一级缓存:singletonObjects,存放完成品对象
单例池,存放已经经历了完整生命周期的 Bean对象
⭐ 第二级缓存:earlySingletonObjects,存放半成品对象
早期单例对象的高速缓存,表示 Bean 的生命周期还没走完(Bean 的属性还未填充)就把这 个Bean 存入该缓存中,也就是实例化但未初始化的 Bean 放入该缓存里。同时也保证了单例,不会重复创建。
⭐ 第三级缓存:Map<String, ObjectFactory<?>> singletonFactories,存放 lambda 表达式
单例工厂的高速缓存,存放可以生成 Bean 的工厂。假如 A 类实现了FactoryBean,那么依赖注入的时候不是 A 类,而是 A 类产生的 Bean。
# 3.2 二级缓存解决循环依赖
只使用两级缓存能否解决循环依赖呢?其实是可以的,但是要保证对象没有经过 AOP 增强,下面来说说原理。
我们来重新看一下循环依赖的问题:
步骤如下:
- 创建 A 对象
- 实例化 A 对象,此时 b=null
- 给 A 对象的 b 属性赋值,也就是依赖注入
- 判断 B 对象是否存在,此时 B 对象不存在
- 创建 B 对象
- 实例化 B 对象,此时 a=null
- 给 B 对象的 a 属性赋值,也就是依赖注入
- 判断 A 对象是否存在,此时 B 对象不存在
- 重复步骤 1 - 9
想要打破循环依赖问题,可以在步骤 9 的地方打破循环。
此时可以引入两个缓存(Map),一级缓存 singletonObjects 存储完整对象,二级缓存 earlySingletonObjects 存储半成品对象。
步骤如下:
- 创建 A 对象
- 实例化 A 对象,此时 b=null
- 将半成品 A 对象放入二级缓存
- 给 A 对象的 b 属性赋值
- 判断一级缓存和二级缓存中是否有 B 对象,此时没有
- 创建 B 对象
- 实例化 B 对象,此时 a=null
- 将半成品 B 对象放入二级缓存
- 给 B 对象的 a 属性赋值
- 判断一级缓存中是否有 A 对象,没有
- 判断二级缓存中是否有 A 对象,有
- 将二级缓存中的 A 对象赋值给 B 对象的 a 属性
- 此时 B 对象完成了创建,将其从二级缓存移到一级缓存
- 回到步骤 4,给 A 对象的 b 属性赋值
- 判断一级缓存中是否有 B 对象,有
- 将一级缓存中的 B 对象赋值给 A 对象的 b 属性
- 此时 A 对象完成了创建,将其从二级缓存移到一级缓存
这里为什么要使用两个缓存呢,因为要保证只有经历了完整生命周期的 Bean 对象才放入单例池(一级缓存)中,如果半成品对象也放入单例池中,可能会从单例池中取出半成品的 Bean 对象导致出错。所以,成品对象和半成品对象分开放。
# 3.3 三级缓存解决循环依赖
假设,A 和 B 都进行了 AOP,此时在进行上面的步骤:
经过上面的操作后,我们可以发现:
- 代理 A 对象中包含代理 B 对象,正确
- 代理 B 对象中包含普通 A 对象,错误,也就是说 B 对象中没有将最终的代理 A 对象注入进去,而是在之前注入了一个普通对象。
出现这个问题的原因是:当循环依赖出现时,未经历 AOP 的对象就被注入到了其他 Bean 对象中。
解决方案:当循环依赖出现时,将被注入的对象提前进行 AOP 增强
Spring 不知道在创建 Bean 的过程中,是否会出现循环依赖,是否会进行 AOP,所以将创建 Bean 的过程写成一个 lambda 表达式放入三级缓存当中。当需要的时候可以通过这个 lambda 表达式创建对象。
详细流程
- 开始创建 A 对象
- 实例化 A 对象
- 将 lambda 表达式写入三级缓存中
- 为 A 对象填充属性
- 扫描发现 A 对象依赖 B 对象,此时容器中没有 B 对象
- 开始创建 B 对象
- 实例化 B 对象
- 将 lambda 表达式写入三级缓存中
- 为 B 对象填充属性
- 扫描发现 B 对象依赖 A 对象,判断容器中是否有 A 对象
- 分别判断一级、二级、三级缓存中是否有 A 对象,在三级缓存中有 A 的 lambda 表达式
- 执行 lambda 表达式,如果有 AOP 增强就返回 A 的代理对象,否则就返回 A 的原始对象
- 将 A 从三级缓存移动到二级缓存
- 给 B 对象中的 a 属性进行赋值,把 A 对象注入进去,此时 B 已经完成了创建
- 将 B 对象放到一级缓存,删除二级和三级缓存中的 B 对象。
- 给 A 对象中的 b 属性进行赋值,把 B 对象注入进去,此时 A 已经完成了创建
- 将 A 对象放到一级缓存,删除二级和三级缓冲中的 A 对象。
简单过程
A 创建过程需要 B,于是A将自己放到三级缓存里面,去实例化 B
B 实例化的时候发现需要 A,于是 B 先查一级缓存,没有,再查二级缓存,没有,再查三级缓存,找到了 A(执行 Lamda 表达式),然后把三级缓存里面的 A 移动二级缓存里。
B 初始化完毕,将自己放到一级缓存(此时 B 里面的 A 依然是创建中状态)。
继续创建 A,此时 B 已经创建结束,直接从一级缓存里面拿到 B,完成创建,并将 A 放到一级缓存中。
# 4. 源码测试
# 4.1 环境搭建
配置 Spring 的环境,创建以下内容:
A 类里面包含 B 类
public class A {
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
2
3
4
5
6
7
8
9
10
11
B 类里面包含 A 类
public class B {
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
2
3
4
5
6
7
8
9
10
11
注解配置,创建 a 和 b 两个 bean 对象,并为他们注入属性。
<bean class="com.zqc.domain.A" id="a">
<property name="b" ref="b"/>
</bean>
<bean class="com.zqc.domain.B" id="b">
<property name="a" ref="a" />
</bean>
2
3
4
5
6
启动类,通过注解创建 Spring 容器。
public class SpringDemo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
A bean = context.getBean(A.class);
System.out.println(bean);
}
}
2
3
4
5
6
7
# 4.2 源码
Debug:创建过程的关键方法:getBean、doGetBean、getSingleton、createBean、doCreateBean、createBeanInstance、populateBean、addSingleton
从 Spring 创建容器开始:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
2
3
4
5
6
7
8
9
10
找到其中的 refresh() 方法,refresh() 是创建容器的核心方法,在该方法中找到 finishBeanFactoryInitialization(beanFactory)
,该方法用来实例化所有非懒加载的单例。在该方法中的最后一行找到 beanFactory.preInstantiateSingletons()
,真正用来实现所有非懒加载的单例。
public void preInstantiateSingletons() throws BeansException {
...
// 获取需要实例化的 bean 的名称
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) { // 遍历创建
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) { // if 不成立
...
}
else {
// 执行到这里
getBean(beanName);
}
}
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
第一次运行到这段代码的时候,beanNames 包含 a 和 b 两个字符串,也就是说会通过这个方法创建 A 和 B 的 bean对象。该方法最终调用到了 getBean(beanName)
方法。
下面再继续看 getBean()
方法
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
2
3
getBean()
方法会调用 doGetBean()
方法来完成相关功能吗,doGetBean() 方法还是挺多的,我们只看其中一部分。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 先看看这个 bean 有没有
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
...
}
else {
...
try {
...
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
...
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
...
}
catch (BeansException ex) {
...
}
}
...
return (T) bean;
}
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
在 doGetBean()
方法中,首先会尝试使用 getSingleton()
方法来获取 bean 对象,我们来看看能否获取到:
// beanName 为 "a"
public Object getSingleton(String beanName) {
return getSingleton(beanName, true); // 调用重载方法,执行下面的方法
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName); // 从单例池中获取,null
// singletonObject == null 成立 true
// isSingletonCurrentlyInCreation("a") 单例 a 当前正在创建 不成立 false
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
...
}
return singletonObject; // 所以直接返回 null
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
所以 Object sharedInstance = getSingleton(beanName)
后,sharedInstance 为 null。最终会来到 doGetBean 中的这段代码:
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
...
}
});
...
}
2
3
4
5
6
7
8
9
10
11
12
同样通过 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
方法来获取单例对象,但是第二个参数传进去了一个 lambda 表达式,这个 lambda 表达式用于创建 bean 对象。也就是说,如果 getSingleton 无法获取到对象的时候会通过这个 lambda 表达式中的 createBean 方法来创建对象。
ObjectFactory 是函数式接口,有且仅有一个方法,可以当作方法的参数传递进去,当指明此类型参数的方法,可以传入一个 lambda 表达式,在执行此行代码的时候并不会执行 lambda 表达式,而是在调用 getObject 方法时才会执行 lambda 表达式的处理逻辑。
下面我们来看看这个 getSingleton()
如何调用这个 lambda 表达式创建对象的。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
...
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName); // 从单例池中获取 bean 对象,得不到,返回 null
if (singletonObject == null) { // if 成立
...
try {
singletonObject = singletonFactory.getObject(); // 执行 getObject(),就又回到了 lambda 表达式
// lambda 表达式执行完毕后要回到这里继续运行
newSingleton = true;
}
...
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
通过 singletonObject = singletonFactory.getObject()
语句运行了 lambda 表达式,不过要记得 lambda 表达式运行完毕后回到这里,在这里插个旗帜【🚩标记1】。
下面我们再看看这个 lambda 表达式。
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
...
}
});
2
3
4
5
6
7
8
其实就是执行了 createBean(beanName, mbd, args)
方法。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
...
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args); // 使用 doCreateBean 创建 Bean 对象
...
return beanInstance;
}
...
}
2
3
4
5
6
7
8
9
createBean()
方法又调用 doCreateBean()
方法,终于到重点部分了,开始创建 bean 对象。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
...
// 通过反射创建 bean 的实例
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 包装一下
final Object bean = instanceWrapper.getWrappedInstance();
...
// 判断是否为早期暴露的单例 Bean
// 是单例、允许循环依赖、当前 beanName 也就是 ”a" 处于正在创建阶段
// 所以 earlySingletonExposure = true
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
...
// 这里又是一个 lambda 表达式,将它加入到三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 目前,三级缓存中包含了 a
}
// 初始化 bean 实例
Object exposedObject = bean;
try {
// 赋值属性
populateBean(beanName, mbd, instanceWrapper);
// 初始化 bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
...
return exposedObject;
}
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
在 doGetBean()
方法中
- 通过
createBeanInstance(beanName, mbd, args)
方法实例化 bean 对象。 - 通过
addSingletonFactory()
方法将「获取 a 的 早期 bean 引用的 lamba表达式」加入到三级缓存,用于解决后面可能出现的循环依赖问题。 - 通过
populateBean()
方法赋值属性。就是要给 a 对象的 b 属性进行赋值。 - 通过
initializeBean()
方法初始化 bean 对象。
如何实例化 bean 对象的过程就不关注了,我们主要看看如何为 a 对象进行属性赋值,看看 spring 如何解决循环依赖问题。下面看看 populateBean()
方法:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
...
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
...
// 如果 pvs 不为 null,就应用这些值
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
2
3
4
5
6
7
8
9
10
11
12
下面看看 applyPropertyValues()
方法
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
...
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
...
// 如果有必要的话,解析一下这个值,这里一定是要解析这个 b 的值
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
...
}
}
...
// Set our (possibly massaged) deep copy.
// 将属性赋值
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
....
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
通过 valueResolver.resolveValueIfNecessary(pv, originalValue)
方法去解析
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
if (value instanceof RuntimeBeanReference) { // 成立
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
...
}
2
3
4
5
6
7
8
9
由于 value 是 RuntimeBeanReference 类型,所以会去执行 resolveReference(argName, ref)
方法。
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
Class<?> beanType = ref.getBeanType();
if (ref.isToParent()) {
...
}
else {
String resolvedName;
if (beanType != null) {
...
}
else {
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
// 熟悉的方法 getBean
bean = this.beanFactory.getBean(resolvedName);
}
this.beanFactory.registerDependentBean(resolvedName, this.beanName);
}
...
return bean;
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
因为要给 a 对象的 b 属性赋值,所以这里需要去容器中获取 b 对象。所以执行 this.beanFactory.getBean("b")
方法,下面又回到了熟悉的 getBean()
流程。第一次调用 getBean()
是为了创建 a ,目前 a 还没有创建完,现在又调用了 getBean()
,目的是为了获取 b。
那么如何获取 b 呢?有一段与创建 a 相似的流程。
getBean()
调用 doGetBean()
方法
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 先看看这个 bean 有没有,返回 null
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
...
}
else {
...
try {
...
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
...
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
...
}
catch (BeansException ex) {
...
}
}
...
return (T) bean;
}
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
getSingleton("b")
获取对象失败,又来到了 getSingleton(beanName, lambda表达式)
方法,进入 getSingleton()
方法
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
...
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName); // 从单例池中获取 bean 对象,得不到,返回 null
if (singletonObject == null) { // if 成立
...
try {
singletonObject = singletonFactory.getObject(); // 执行 getObject(),就又回到了 lambda 表达式
newSingleton = true;
}
...
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
执行 getObject()
又是调用 lambda 表达式的 createBean()
方法,createBean()
方法又调用 doCreateBean()
方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
...
// 通过反射创建 bean 的实例
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 包装一下
final Object bean = instanceWrapper.getWrappedInstance();
...
// 判断是否为早期暴露的单例 Bean
// 是单例、允许循环依赖、当前 beanName 也就是 ”a" 处于正在创建阶段
// 所以 earlySingletonExposure = true
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
...
// 这里又是一个 lambda 表达式,将它加入到三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 目前,三级缓存中包含了 a
}
// 初始化 bean 实例
Object exposedObject = bean;
try {
// 赋值属性
populateBean(beanName, mbd, instanceWrapper);
// 初始化 bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
...
return exposedObject;
}
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
此时开始创建 B 对象,相当于在创建 A 对象的过程中嵌套创建了 B 对象。接着看 B 对象复制属性 populateBean()
,嵌套调用 applyPropertyValues(beanName, mbd, bw, pvs)
赋值属性,嵌套调用 resolveValueIfNecessary(pv, originalValue)
解析属性,嵌套调用 resolveReference(argName, ref)
解析属性:
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
Class<?> beanType = ref.getBeanType();
if (ref.isToParent()) {
...
}
else {
String resolvedName;
if (beanType != null) {
...
}
else {
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
// 熟悉的方法 getBean
bean = this.beanFactory.getBean(resolvedName);
}
this.beanFactory.registerDependentBean(resolvedName, this.beanName);
}
...
return bean;
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
再一次的来到了 getBean()
方法:
第一次 getBean()
:为了创建 A 对象。
第二次 getBean()
:为了给 A 对象的 B 属性赋值,需要获取 B 对象,其实就是创建 B 对象。
第三次 getBean()
:为了给 B 对象的 A 属性赋值,需要获取 A 对象。
getBean()
方法调用 doGetBean()
方法:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 这一次看看 getSingleton("a") 能否获取到
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
...
}
else {
...
try {
...
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
...
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
...
}
catch (BeansException ex) {
...
}
}
...
return (T) bean;
}
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
调用 getSingleton()
方法
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName); // 单例池中没有
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 正在创建的对象成立
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName); // 二级缓存中也没有
if (singletonObject == null && allowEarlyReference) { // 成立
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); // 从三级缓存中获取
if (singletonFactory != null) { // 成立
singletonObject = singletonFactory.getObject(); // 执行三级缓存中存入的 lambda 表达式
// 执行完记得回到这里
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
当时将 getEarlyBeanReference()
放入三级缓存:
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
此时调用 getObject()
将执行 getEarlyBeanReference()
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean; // 暴露对象
// 如果对象有后置处理的话,就对他进行 AOP 增强
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
// 返回处理后的对象
return exposedObject;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
如果我们对这个 Bean 对象进行后置处理的话,那么会提前进行 AOP 增强,并返回增强后的代理对象,如果没有 AOP 增强的话,那就返回原来的对象。回到刚刚的 getSingleton()
方法:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
..
singletonObject = singletonFactory.getObject(); // 执行完毕,成功获取 a 对象
this.earlySingletonObjects.put(beanName, singletonObject); // 放入二级缓存
this.singletonFactories.remove(beanName); // 从三级缓存中移除
}
}
}
}
return singletonObject; // 返回 a 对象
}
2
3
4
5
6
7
8
9
10
11
在 doGetBean()
方法中返回 a 对象
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName); // 获取a 对象成功
if (sharedInstance != null && args == null) { // 成立
...
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
...
return (T) bean; // 返回 a 对象
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
再一次回到 resolveReference()
,之前我们在这里解析 a 属性,因为要给 B 对象的 a 属性赋值
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
...
else {
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
bean = this.beanFactory.getBean(resolvedName); // 获取 a 对象成功
}
this.beanFactory.registerDependentBean(resolvedName, this.beanName);
}
...
return bean; // 返回 a 对象
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
再一次回到 resolveValueIfNecessary()
方法
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref); // 返回 a 对象
}
...
}
2
3
4
5
6
7
再一次回到 applyPropertyValues()
方法,之前我们调用这个方法是为了给 B 对象的 a 属性赋值。
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
...
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
...
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); // 这里返回了 a 对象
...
}
}
...
// Set our (possibly massaged) deep copy.
// 将属性赋值
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy)); // 这里完成赋值
}
....
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
此时执行完 bw.setPropertyValues(new MutablePropertyValues(deepCopy))
代码后,B 对象里面就包含了 a 属性。
此时再回到 doCreateBean()
方法继续完成 B 对象的初始化,并返回 B 对象到 createBean()
方法,再返回到 getSingleton()
方法
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
...
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
...
try {
singletonObject = singletonFactory.getObject(); // 刚刚从这里获取了 b 对象
newSingleton = true;
}
...
if (newSingleton) {
addSingleton(beanName, singletonObject); // 添加到单例池中
}
}
return singletonObject;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
下面看看 addSingleton(beanName, singletonObject)
方法:
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);
}
}
2
3
4
5
6
7
8
到目前位置,b 对象在一级缓存,a 对象在二级缓存,b 对象已经完成创建,a 对象还处于正在创建阶段。
返回 b 对象到 doGetBean()
方法,再返回到 getBean()
方法,再次回到 resolveReference()
,这一次继续完成对 A 对象 b 属性的赋值。
此时,b 对象已经完成创建过程,它的创建过程是嵌套在 a 对象创建中。后面,a 对象也会继续采用同样的方法完成创建。
# 4.3 总结
# 5. 疑问
第三级缓存的作用?
Bean
的生命周期可知,Bean
初始化是经过了实例化(createBeanInstance
)、属性注入(populateBean
)、后置处理器与生命周期方法(initializeBean
)三个步骤处理,最终才得到一个创建完成的 Bean
。
protected Object doCreateBean(...) throws BeanCreationException {
...
// 实例化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
final Object bean = instanceWrapper.getWrappedInstance();
// 解决循环依赖的一步:将获取Bean(提前进行AOP)的操作放入三级缓存
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 初始化Bean
Object exposedObject = bean;
try {
// 属性注入
populateBean(beanName, mbd, instanceWrapper);
// 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在循环依赖时,在属性注入(populateBean
)步骤就要解决依赖问题,
而 AOP 代理是在初始化(initializeBean
)步骤中通过后置处理器实现的。
如果严格按照 Bean
的这个生命周期执行,依赖注入是无法注入代理之后的对象的。
Spring
引入了三级缓存,在实例化对象之后,进行属性注入之前,将实现 AOP 代理的步骤封装为 Bean
工厂放进三级缓存。
如果这个对象被循环依赖了,则使用工厂提前进行 AOP 代理,如果没有被循环依赖,则这个工厂就不会被使用。
为什么第三级缓存要用lambda表达式?不可以直接调用方法吗?