循环依赖可以是自己依赖自己,两对象相互依赖,多个对象之间的间接依赖三种情况。
循环依赖主要场景:单例setter注入、多例setter注入、构造器循环依赖、生产代理对象产生的循环依赖、使用@DependsOn产生的循环依赖。
- spring解决单例的setter注入
通过spring的三级缓存:
// 一级缓存,用于保存实例化、注入和初始化完成的bean实例。该缓存中的bean可以直接使用
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
// 二级缓存,用于保存实例化完成的bean实例(尚未填充属性),用于解决循环依赖
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
// 三级缓存,用于保存bean工厂对象,用于解决循环依赖
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
获取bean的主要方法:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 首先从一次缓存中取
Object singletonObject = this.singletonObjects.get(beanName);
// 如果一级缓存中没取到, 并且对象正在创建中
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
// 然后从二级缓存中取
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果二级缓存没取到, 且允许singletonFactories通过getObject()获取
if (singletonObject == null && allowEarlyReference) {
Map var4 = this.singletonObjects;
synchronized(this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 最后从三级缓存中取
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 提前曝光bean实例(raw bean),用于解决循环依赖
singletonObject = singletonFactory.getObject();
// 如果获取到就放入二级缓存, 并且从三级缓存中移除
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
A和B相互依赖:
从一级缓存中获取A实例,如果获取不到,A首先完成初始化的第一步,并提前暴露到singletonFactories中。
接着进行A初始化第二步,发现自己依赖B,尝试去get(B),发现B还没有创建。
于是B开始初始化,进行初始化第二步时发现自己依赖A,于是尝试get(A)、尝试一级缓存获取、尝试从二级缓存获取都没有,尝试从三级缓存获取A对象,拿到了还没有初始化完全的A。
B拿到A后顺利完成初始化阶段2、3,最终A也完成了初始化。
- 多例循环依赖问题可以通过把bean改成单例
- 构造器循环依赖通过使用
@Lazy
注解 - 生成代理对象产生的循环依赖可以使用
@Lazy
注解,延迟加载或是使用@DependsOn
注解,指定加载先后关系或是修改文件名称,改变循环依赖类的加载顺序 - 使用@DependsOn产生的循环依赖找到
@DependsOn
注解循环依赖的地方,迫使它不循环依赖