Spring Boot 如何解决循环依赖

什么是循环依赖

如图,循环依赖指的是两个或者多个对象互相持有对方的引用,导致形成了一个闭环,代码类似如下

1
2
3
4
5
6
7
8
9
10
class A {
@Autowired
private B b;
}

class B {
@Autowired
private A a;
}

循环依赖带来的问题

如果是以前的引用计数器的方式管理内存,会导致计数器的个数最少为1,因为互相引用这对方,导致了计数器无法清零,而引用计数器的内存管理方式是只有当计数器的个数清零后才可以释放。

如何解决循环依赖

Spring Boot解决循环依赖的问题是通过三级缓存中的,二级缓存,提前暴露未完全初始化的对象。

因为在Bean容器初始化一个对象的过程,并不是调用了一个构造后就会立马返回使用,它会把对象放在一个叫做提前暴露的集合中,然后等待着去填充对象中依赖的属性,具体位置在 AbstractAutowireCapableBeanFactory.java -> doCreateBean 方法中有一个populateBean 方法调用

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
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
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 (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}

Spring Boot 三级缓存

  • singletonObjects
    存放完全实例化后的对象,这个时候的对象是一个完整的对象
  • earlySingletonObjects
    提前暴露的对象,存放的是已经实例化,但是还没有填充注入的属性的对象,是一个半成品的对象
  • singletonFactories
    存放着需要引入AOP的对象的工厂类,返回的是AOP之后代理对象的地址
Author: Gavin Zhao
Link: https://www.gavinz.xyz/2022/01/11/spring-boot-如何解决循环依赖/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.