1. 目录

[TOC]

2. 说明

spring 解决循环依赖主要用到三层缓存,即singletonObjectsearlySingletonObjectssingletonFactories三个缓存,此三个缓存是三个Map作为DefaultSingletonBeanRegistry的成员属性

  • singletonObjects类型是ConcurrentHashMap
  • earlySingletonObjects类型是ConcurrentHashMap
  • singletonFactories类型是HashMap

3. 依赖分析

18728d002ad014504d1291ef4220512f

DefaultSingletonBeanRegistry 是单例bean的容器类,bean存储相关的都在此,我们应用中的BeanFactoryApplicationContext都继承于此。

其方法主要实现了单例bean的获取,其中包含了创建bean的匿名实现,即传入ObjectFactory,内部getSingleton方法的逻辑中会在没有拿到数据的时候调用getObject()方法,从而调起外部传入的创建bean的方法,再保存在单例容器中。上图中是getSingleTon(String,ObjectFactory<?>)addSingleTon(String,ObjectFactory<?>)两个方法。
创建bean的逻辑则主要是在子类AbstractBeanFactory中,内部包含了createBean()doCreateBean()等方法,其匿名内部类的实现也是doBean()方法。
AbstractBeanFactory本身也会继承DefaultSingletonBeanRegistry,因此,AbstractBeanFactory也具有维护容器的能力

4. 源码分析

源码部分我们就主要拿重点的部分讲解了,其实也就是整合getBean和createBean两个逻辑提取,主要的类为AbstractBeanFactory

首先,实例化单例bean循环调用getBean()方法,而getBean方法直接调用doGetBean,首先会从容器中获取,如下:

4.1. 获取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
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly
) throws BeansException {

//此处逻辑是首先从单例容器中拿,拿不到则会从二级缓存中拿,拿不到则从三级缓存中拿,而三级缓存中如果有则会调用创建bean的方法得到bean,并将其加入二级缓存,从三级中移除,具体逻辑见 <1.获取单例bean>
//刚开始肯定是拿不到的,因此会走没有bean的逻辑
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//一般第一次走这里会继续创建
else {
//继续获取bean,但是带上创建回调,具体逻辑见 <2.获取单例bean>
//此处只从一级缓存中获取,获取到有就返回了;
// 没有的话则调用匿名内部类方法,创建并设置到一级缓存中,并从二级三级缓存中移除
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}

4.2. 创建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
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
//前面拿bean定义等
//......

//开始创建
return doCreateBean(beanName,mbd,args)
}
//只保留核心
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
//拿到实例化的bean
Object bean = instanceWrapper.getWrappedInstance();
Object exposedObject = bean;
// 添加到三级缓存中
// 此处有一个匿名内部类调用,但还是把原来实例化的bean传入了的,动态代理会用到此处逻辑
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
//填充bean,这里如果有依赖bean的话就会执行getBean()初始化下一个bean
populateBean(beanName, mbd, instanceWrapper);
//初始化bean
// 初始化Aware
// -> 执行BeanPostProcessor(包含了ApplicationContextAware、@PostConstruct)
// -> 执行 InitialBean.afTerproperties()
exposedObject = initializeBean(beanName, exposedObject, mbd);

//earlySingletonExposure 的值是满足是单例bean、允许循环依赖、正在创建
if (earlySingletonExposure) {
//获取单例bean,这个和 1.1的获取单例一个方法,只是这里不再从三级缓存中获取了
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
}
}
}
return exposedObject;
}

4.3. 单例容器的方法

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
// 1. 获取单例bean
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
//1.1 这里简化了双重检测锁的逻辑,更直观获取bean的逻辑
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//一级缓存中获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//二级缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//三级缓存中获取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//注意:此处会调用匿名内部类的方法,创建bean并返回
singletonObject = singletonFactory.getObject();
//添加到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
//从三级缓存中移除
this.singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
//2. 获取单例bean
//此处省略了生成前的校验,异常处理等,只留了核心逻辑
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
//一级缓存中获取bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
boolean newSingleton = false;
//没有获取到则调用创建
singletonObject = singletonFactory.getObject();
newSingleton = true;
if (newSingleton) {
//添加到容器缓存中,并从二级三级缓存中移除
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//3.添加一级缓存
protected void addSingleton(String beanName, Object singletonObject) {
//添加到一级缓存中
this.singletonObjects.put(beanName, singletonObject);
//从二级,三级中移除
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
//4.添加到三级缓存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
//添加三级缓存并从二级缓存中移除
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

5. 流程分析

5.1. 普通Bean下的循环依赖

通过上面的分析, 我们通过实例进一步了解。

对于A(B,C),B(A,C)即A类中有属性BC,B类中有属性AC

假如首先getBean()初始化A,且允许循环依赖

  1. (A)调用getSingleton(beanName,true)获取A的单例,此时三层缓存中都没有,因此获取不到。
    A-无缓存,B-无缓存
  2. (A)调用getSingleton(beanName, () -> {return createBean(beanName, mbd, args);}方法,此时从一级缓存中也拿不到,然后就会调用内部方法createBean()。完成之后再加入一级缓存,从三级缓存移除(此处待机,等待回调)。
    A-无缓存,B-无缓存
  3. (A)调用createBean()创建bean,首先实例化bean,然后调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));加入到三级缓存中,并从二级缓存移除。
    注意必须开启循环依赖才会进入addSingletonFactory()方法,因此无循环依赖的不会加入到三级缓存中,步骤6则拿不到缓存,进而循环,报循环错误
    注意此时已经实例化的bean在getEarlyBeanReference()
    A-三级缓存,B-无缓存
  4. (A)populateBean()此时填充bean,开启对象B的getBean()
    A-三级缓存,B-无缓存
  5. (B) B还未生成bean,同样执行前面4个逻辑,到了populateBean(),准备注入A
    (1)A-三级缓存,B-无缓存
    (2)A-三级缓存,B-无缓存
    (3)A-三级缓存,B-三级缓存
    (4)A-三级缓存,B-三级缓存
  6. (B) 再调用A的getBean() -> getSingleton(beanName,true)时,由于A已经在三级缓存中了,因此这里能够取到值,然后将A添加到二级缓存,从三级缓存中移除,并且返回A
    A-二级缓存,B-三级缓存
    注意此处的三级缓存实际是第三步的匿名内部类,但是对于普通的bean,返回的仍然是原来的bean,此处是处理代理类的
  7. (B) B注入A则可以成功,继续装配B,执行初始化流程initializeBean()等;
    注意 在初始化initializeBean()过程中B会调用AnnotationAwareAspectJAutoProxyCreator这个BeanPostProcessor执行代理方法wrapIfNecessary(),得到代理后的Bean
    A-二级缓存,B-三级缓存
  8. (B) B通过getSingleton(beanName, false)拿一次一二级缓存中的bean,由于B此时在三级缓存中,因此获取不到,还是按照步骤7中的返回,但此时B已经注入了A、完成组装,而且已经是代理后的Bean。
    A-二级缓存,B-三级缓存
  9. (B) B回到步骤2,加入B到一级缓存,并从二三级缓存中移除。
    A-二级缓存,B-一级缓存
  10. (A) 回到A注入B处,A注入B成功,继续执行初始化流程等
    注意 此处执行初始化时A也会像B的步骤7一样进入AnnotationAwareAspectJAutoProxyCreator,但是缓存中有是否已经代理过了,代理过了则不代理了,因此不会再代理一次,此处返回不代理的结果。
    A-二级缓存,B-一级缓存
  11. (A) A通过getSingleton(beanName, false)拿一次一二级缓存中的bean,由于A在二级缓存中了,此处可以得到A,返回A,然后返回此处的Bean。
    A-二级缓存,B-一级缓存
  12. (A) 回到步骤2,加入A到一级缓存,并从二三级缓存中移除。
    A-一级缓存,B-一级缓存

这样就解决了循环依赖,其实我们可以发现步骤3getEarlyBeanReference()这里匿名内部类加入三级缓存,然后在步骤6第二次对AgetBean时加入二级缓存,最后再回到步骤2加入一级缓存,这里看只需要二级缓存,不要三级缓存也是一样的,而且步骤3也没必要在弄一个匿名内部类。
但是,我们这里没有说到动态代理的情况,spring下很多地方都会用到动态代理。动态代理是在getEarlyBeanReference()有特殊处理的,见下

5.2. 动态代理下的循环依赖

对于A(B),B(A)且C代理A,D代理B,则包含关系有C(A(B)),D(B(A))

对于上述关系,实际上B因为被D代理了的,因此A中的B应该为 D(B)才合理,因此正确的应该为C(A(D(B))),同理得到D(B(C(A)))
假设用E代替C(A),F代替D(B),则他们的循环关系应该为 E(F(E(F...))),即E->F->E
简单的来说就是他们互相的属性字段应该为代理后的对象。

对于上述的普通循环代理,我们可以得知:

  • 步骤3 getEarlyBeanReference()是在三级缓存中的匿名内部类,
  • 步骤6 从三级缓存中去拿的时候调用内部方法,通过AbstractAutoProxyCreator#getEarlyBeanReference调用wrapIfNecessary()生成代理对象(这个在AOP动态代理分析处解析,专门生成动态代理的)。此时,我们加入二级缓存中的A对象已经是代理之后的对象E了。
  • 步骤7 B中装配的实际上就是代理之后的对象E
  • 步骤7 的执行初始化流程initializeBean()会循环调用applyBeanPostProcessorsAfterInitialization()方法,此方法会调用AbstractAutoProxyCreator#postProcessAfterInitialization(),进而调用wrapIfNecessary(),此时生成B的代理对象F
  • 步骤8 由于上述改变了B的返回对象为F,因此步骤8返回的为F
  • 步骤9 加入到一级缓存中的则为F,同时删除三级缓存,由于B并没有执行三级缓存的读取,因此 步骤5(3) 加入的getEarlyBeanReference()并没有生效,保证了只执行了一次创建代理wrapIfNecessary()流程
  • 步骤11 A在执行此步骤之前也会像B一样
  • 其余流程均为一致

此处可以发现,A和B创建代理wrapIfNecessary()的入口方法不同,A是在三级缓存中匿名内部类getEarlyBeanReference()调起创建,而B则是在初始化方法完成时的后处理中postProcessAfterInitialization()
其原因是A是在填充属性populate()中调用的B;B是先调用A,在B的填充A时候调用getBean()获取A的时候就代理了A,也保证了B中的A是代理之后的;B填充A完成之后初始化自身时的后处理器代理了B。再到A的初始化自身的后处理时A已经被代理过了,不用再重新生成。

此处还有一个知识点:B拿到A的代理对象F时,实际上F里有A的实例bean,虽然F不会被修改了,但是后续B初始化完成后初始化A时,F中的A保持着引用,而动态代理执行方法时最终也会调用到源类型,因此才保证了相互持有的代理

以下是画了一个带代码的流程图,可以看一下

循环依赖流程图

6. 总结

首先分析无动态代理的循环依赖,主要是在容器之间的一个对缓存的处理,利用了java引用的特性,保证地址空间互相引用到,然后就可以初始化自身了。
同样有动态代理下的也利用了java的引用特性,才保持了代理类可以相互注入并保持循环依赖
同时需要注意两个代理类的实际也都不一样,虽然都是调用了wrapIfNecessary()实现动态代理,但是A是在B调用A的时候AgetBean()中调用三级缓存匿名内部类调起的,而B是在B自身创建initialize()中通过postProcessAfterInitialization()完成。

7. 注意事项

网上大部分都只是说getEarlyBeanReference()是解决循环依赖的,实际上这并不准确。因为单纯的解决循环依赖也不需要三级缓存,两级也可以实现的,而且也不需要getEarlyBeanReference()匿名内部类。
准确的来说应该是getEarlyBeanReference()是为了解决动态代理下的循环依赖的。Spring的思想就是在生命周期的最后执行AOP代理,而不是在创建的时候就执行代理,对于循环依赖必须要提前执行代理,因此才需要二级缓存提前完成代理,对于不需要循环依赖的,则二级缓存无意义,压根就没有使用;