本文用简要代码事例解释了Spring如何能解决依赖循环,并不讨论实际源码涉及的诸多因数,比如为什么有3个集合。
重点:
1、用3个集合来解决循环依赖,需要清楚3个集合分别是存什么
2 、开始条件 :使用
Supplier来延迟 Bean 的创建,确保只有在需要时才创建 Bean。看下代码中private Map<String, Supplier<?>> singletonFactories = new HashMap<>();
3 、**查找顺序:**①先从singletonObjects 找,②找不到再从earlySingletonObjects找,③再找不到从singletonFactories创建并放到earlySingletonObjects中。假设这个方法叫getBean。
4 、结束条件:从singletonFactories创建的时候遇到依赖会调用getBean获取 ,这相当于递归过程 。当遇到依赖循环的时候,递归会在调用步骤②的时候结束。相当于结束条件。
模拟代码:
java
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
class A {
private B b;
public void setB(B b) {
this.b = b;
}
@Override
public String toString() {
return "A{" +
"b=" + (b != null ? "B" : "null") +
'}';
}
}
class B {
private A a;
public void setA(A a) {
this.a = a;
}
@Override
public String toString() {
return "B{" +
"a=" + (a != null ? "A" : "null") +
'}';
}
}
public class CircularDependencyDemo {
private Map<String, Object> singletonObjects = new HashMap<>();
private Map<String, Object> earlySingletonObjects = new HashMap<>();
private Map<String, Supplier<?>> singletonFactories = new HashMap<>();
public static void main(String[] args) {
CircularDependencyDemo demo = new CircularDependencyDemo();
demo.resolveCircularDependency();
}
public void resolveCircularDependency() {
//创建 A 的工厂并放入 singletonFactories
singletonFactories.put("a", () -> {
A a = new A();
earlySingletonObjects.put("a", a);
//初始化 A 时发现需要 B
a.setB(getBean("b"));
return a;
});
//创建 B 的工厂并放入 singletonFactories
singletonFactories.put("b", () -> {
B b = new B();
earlySingletonObjects.put("b", b);
//初始化 B 时发现需要 A
b.setA(getBean("a"));
return b;
});
//初始化 A 和 B
A a = getBean("a");
B b = getBean("b");
//完成初始化后将 A 和 B 移动到 singletonObjects
singletonObjects.put("a", a);
singletonObjects.put("b", b);
System.out.println(singletonObjects.get("a"));
System.out.println(singletonObjects.get("b"));
}
//查找顺序
private <T> T getBean(String beanName) {
if (singletonObjects.containsKey(beanName)) {
return (T) singletonObjects.get(beanName);
}
if (earlySingletonObjects.containsKey(beanName)) {
return (T) earlySingletonObjects.get(beanName);
}
if (singletonFactories.containsKey(beanName)) {
Supplier<?> factory = singletonFactories.remove(beanName);
T object = (T) factory.get();
//这里隐藏着递归过程
earlySingletonObjects.put(beanName, object);
return object;
}
throw new RuntimeException("Bean not found: " + beanName);
}
}
上面是基本思路,实际源码涉及过程要复杂很多:
实际递归调用并非简单的直接调getSingletion,而是...->doCreateBean->getSingletion
doCreateBean做了以下几件事情
- 实例化 Bean(通过构造函数或工厂方法)
- 提前暴露 ObjectFactory(用于解决循环依赖)
- 填充属性(依赖注入)
- 初始化(调用 init-method、Aware 接口、BeanPostProcessor 等)
- 注册为完整单例


AbstractAutowireCapableBeanFactory .doCreateBean
java
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
//1.实例化 Bean(调用构造函数)
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
final Object bean = instanceWrapper.getWrappedInstance();
// ... 省略部分代码 ...
//2.【关键】判断是否需要提前暴露 ObjectFactory(用于循环依赖)
boolean earlySingletonExposure = (mbd.isSingleton()
&& this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
//3.注册一个 ObjectFactory 到 singletonFactories
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//4.填充属性(populateBean)→ 这里会触发依赖的 Bean 创建(如 A 需要 B)
populateBean(beanName, mbd, instanceWrapper);
//5.初始化(initializeBean)
Object exposedObject = initializeBean(beanName, bean, mbd);
//6.如果提前暴露了,现在要把完整的 Bean 放入 singletonObjects
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 处理代理替换等逻辑...
}
}
return exposedObject;
}
填充属性间接调用了doCreateBean
java
AbstractAutowireCapableBeanFactory.populateBean()
└─> AbstractAutowireCapableBeanFactory.applyPropertyValues()
└─> BeanDefinitionValueResolver.resolveValueIfNecessary()
└─> BeanDefinitionValueResolver.resolveReference()
└─> AbstractBeanFactory.resolveEmbeddedValue() // (非关键)
└─> **AbstractBeanFactory.getBean(String beanName)**
└─> AbstractBeanFactory.doGetBean()
└─> **createBean()**
└─> **doCreateBean()** ← 最终入口