GeekIBLi

SpringBean循环依赖

2021-07-28

Spring Bean 循环依赖

为什么会存在循环依赖

如上图👆所示,A对象的一个属性是B,B对象的一个属性是A,而Spring中的bean默认情况下都是单例的,所以这两个Bean就产生了循环依赖的问题!

那么循环依赖的问题出现在什么情况呢

想一下属性赋值的方式有几种呢?

  • 构造器赋值

    这种形式循环依赖问题无法解决

  • GET/SET方法

    调用SET方法进行赋值的时候,可以通过三级缓存的策略来解决循环依赖的问题

所以,三级缓存的策略是针对于使用SET方法对属性赋值的场景下的!

循环依赖如何解决

在实例化的过程中,将处于半成品的对象全部放到缓存中,方便后续来进行调用;
只要有了当前对象的引用地址,那么后续来进行赋值即可;

d 能不能将创建好的对象也放到缓存中呢?

不能,如果放在一起将无法区分对象是成品对象还是半成品对象了
所以再次引出多级缓存的概念,可以创建两个缓存对象,一个用来存放已经实例化的半成品对象,另一个存放完成实例化并且完成初始化的成品对象,这个应该比较好理解吧!

思考一下以上的设计有没有问题呢?

为什么需要三级缓存?

Spring在解决对象Bean循环依赖的问题的解决方案是使用了「三级缓存」;
为什么需要三级缓存,也就是三个Map对象;

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

1
2
3
4
5
6
// 一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
// 二级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
// 三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);

三级缓存中分别保存的是什么内容

  • 一级缓存: 成品对象
  • 二级缓存: 半成品对象
  • 三级缓存; lambda表达式

如果只有二级缓存可不可行

在Spring源码中,只有addSingleton方法和doCreateBean方法中向三级缓存中添加东西的;

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory

1
2
3
4
5
6
7
8
9
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);
}
}

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}

return singletonObject;
}

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
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized(this.singletonObjects) {
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 (this.logger.isDebugEnabled()) {
this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}

this.beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = this.suppressedExceptions == null;
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet();
}

try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException var16) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw var16;
}
} catch (BeanCreationException var17) {
BeanCreationException ex = var17;
if (recordSuppressedExceptions) {
Iterator var8 = this.suppressedExceptions.iterator();

while(var8.hasNext()) {
Exception suppressedException = (Exception)var8.next();
ex.addRelatedCause(suppressedException);
}
}

throw ex;
} finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}

this.afterSingletonCreation(beanName);
}

if (newSingleton) {
this.addSingleton(beanName, singletonObject);
}
}

return singletonObject;
}
}

Tags: Spring