参考地址: 《Spring IOC 容器源码分析 - 循环依赖的解决办法》 《Spring IOC循环依赖解决方案分析》 《Spring5源码阅读--如何解决循环依赖?》
在 Spring 中获取一个 Bean,是通过获取 BeanDefinition 实现的:在定义 Bean 信息的 XML 文件中,BeanDefinitionReader 读取指定路径下的 XML 文件,获取 Bean 定义信息并封装成 BeanDefinition 对象,该实例对象包含依赖关系信息 dependsOn。通常依赖关系是在 XML 的 p:xxx-ref,或者通过类的 @Autowired 等手段实现的。
循环依赖,就是在 classA 和 classB 的属性中,都互相包含彼此。Spring 避免循环依赖出现的错误,使用了三层缓存:
分析 getSingleton()
方法:
public Object getSingleton(String beanName){
//参数true设置标识允许早期依赖
return getSingleton(beanName,true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//如果为空,则锁定全局变量并进行处理。
synchronized (this.singletonObjects) {
//如果此bean正在加载,则不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//当某些方法需要提前初始化的时候则会调用addSingleFactory 方法将对应的ObjectFactory初始化策略存储在singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//调用预先设定的getObject方法
singletonObject = singletonFactory.getObject();
//记录在缓存中,earlysingletonObjects和singletonFactories互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
依旧以 classA 和 classB 为例,假设两个实例对象存在循环依赖关系,且 classA 对象首先在 Spring 容器中初始化。
至此,循环依赖的 classA 和 classB 都完成了实例化。