1. 循环依赖
1.1. 源码解读
- 类:DefaultSingletonBeanRegistry
- 核心集合:singletonObjects、singletonFactories、earlySingletonObjects、registeredSingletons
private final Map<String, Object> singletonObjects=new ConcurrentHashMap<>(256);
private final Map<String, ObjectFactory<?>>singletonFactories=new HashMap<>(16);
private final Map<String, Object> earlySingletonObjects=new ConcurrentHashMap<>(16);
private final Set<String> singletonsCurrentlyInCreation=
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
- 流程:
- 检测当前 bean 是否在 singletonObjects 中,在则直接返回缓存好的 bean;不在则检测 是否在 singletonFactories 中,在,则调用其 getObject 方法,返回,并从
singletonFactories 中移除,加入到 earlySingletonObjects 中。
- 正常创建,beforeSingletonCreation:检测当前 bean 是否在 singletonsCurrentlyInCreation, 如果存在,抛出异常。表示存在构造器循环依赖。如果不存在,则将当前 bean
加入。
- bean 初始化,分为构造方法初始化、工厂方法初始化和简单初始化。如果是构造方法初 始化,那么递归地获取参数 bean。其他情况不会递归获取 bean。
- addSingletonFactory:如果当前 bean 不在 singletonObjects 中,则将当前 bean 加入到 singletonFactories 中,并从 earlySingletonObjects
中移除。
- 调用用户初始化方法,比如 BeanPostProcesser、InitializingBean、init-method,有可能 返回代理后的 bean。
- 检测循环依赖,如果当前 bean 在 singletonObjects 中,则判断当前 bean(current bean)
与 singletonObjects 中的 bean(cached bean)是否是同一个,如果不是,那么说明当前 bean 是被代理过的,由于依赖当前 bean 的 bean 持有的是对 cached bean
的引用,这是不被允许的,所以会抛出 BeanCurrentlyInCreationException 异常。
- afterSingletonCreation:将当前 bean 从 singletonsCurrentlyInCreation 中删除
- addSingleton: 将当前bean加入到 singletonObjects,然后从singletonFactories, earlySingletonObjects中移除,结束
1.2. 通过构造器注入构成的循环依赖,无法解决,只能抛出异常:BeanCurrentlyInCreationException
- Spring 容器创建单例“A” Bean,首先检测 singletonFactories 是否包含 A,发现没有,于是正常创建,然后检测 A 是否包含在 singletonsCurrentlyInCreation中,没有,则将 A
放入。 构造方法初始化时需要 B 实例(A 尚未放入到 singletonFactories 中),于是调用了 getBean(B)
方法、
- Spring 容器创建单例“B” Bean,首先检测 singletonFactories 是否包含 B,发现没有,于是正常创建,然后检测 B 是否包含在 singletonsCurrentlyInCreation中,没有,则将 B
放入。 构造方法初始化时需要 C 实例(B 尚未放入到 singletonFactories 中),于是调用了 getBean(C)
方法、
- Spring 容器创建单例“C” Bean,首先检测 singletonFactories 是否包含 C,发现没有,于是正常创建,然后检测 C 是否包含在 singletonsCurrentlyInCreation中,没有,则将 C
放入。 构造方法初始化时需要 A 实例(C 尚未放入到 singletonFactories 中),于是调用了 getBean(A)
方法、
- Spring 容器创建单例“A” Bean,首先检测 singletonFactories 是否包含 A,发现没有于是正常创建 ,然后检测A是否包含在 singletonsCurrentlyInCreation 中 , 有 , 抛 出
BeanCurrentlyInCreationException 异常。