为什么会存在循环依赖的问题呢?
假如现在有两个类,A和B,A里面引用了B,B里面引用了A,A初始化的时候会注入B,B还没有创建,就马上开始创建B的过程,在创建B时,又需要注入A,而A还没有创建完成,就形成了循环依赖,也就是循环引用。
Spring循环依赖有三种情况:
注意,循环依赖只能解决singleton注入形成的循环依赖
三级缓存:
//一级缓存,所有初始化好的Bean(可以直接使用)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//二级缓存,根据名称可知,用于存放提前曝光的单例对象的map,实例化还没有填充属性,
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
//三级缓存,单例对象工厂
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
//正在创建中的单例对象的名称集合,创建完成会被移除
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));
//创建成功的单例对象的名称集合
private final Set<String> registeredSingletons = new LinkedHashSet(256);
实例化A(正常实例化)到第十步的时候发现依赖了B,然后在第九步执行了addSingletonFactory()方法
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
...
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized(this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
...
}
在这个方法里面,就将工厂Bean放到了singletonFactories集合里面,执行到这里
//一级缓存
singletonObjects//没有A
//二级缓存
earlySingletonObjects//没有A
//三级缓存
singletonFactories//有A
//正在创建中的单例对象的名称集合
singletonsCurrentlyInCreation//有A
//创建成功的单例对象的名称集合
registeredSingletons//有A
然后执行第十步,发现没有B的实例,就开始创建B,到第十步之前也都是正常流程,
到第十步,当执行到autowireByName()方法时要调用getBean()方法去容器里面找A
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
...
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = this.unsatisfiedNonSimpleProperties(mbd, bw);
String[] var6 = propertyNames;
int var7 = propertyNames.length;
for(int var8 = 0; var8 < var7; ++var8) {
String propertyName = var6[var8];
if (this.containsBean(propertyName)) {
Object bean = this.getBean(propertyName);//调用getBean()
pvs.add(propertyName, bean);
this.registerDependentBean(propertyName, beanName);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Added autowiring by name from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + "' by name: no matching bean found");
}
}
}
...
}
而最终getBean()方法调用getSingleton()方法,这里是重点
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);//一级缓存里面找
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);//二级缓存里面找
if (singletonObject == null && allowEarlyReference) {
//三级缓存里面找
ObjectFactory<?> singletonFactory =(ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//将三级缓存里面的剪切到二级缓存里面
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
}
执行这里时earlySingletonObjects里面是有A的,只是这里面的A是不完美的,还没有完成属性填充,但是已经可以被引用了,最终这里返回A的引用给B,然后B完成初始化,在吧B的引用返回给A,最终A也完成初始化,然后就不存在循环依赖。
为什么构造器注入不能利用三级缓存解决循环依赖问题呢?
因为上面的三级缓存集合singletonFactories的前提就是执行了构造器,所以构造器的循环依赖没法解决。
为什么prototype注入(setter注入原型)不能利用三级缓存解决循环依赖问题呢?
原型注入的意思就是每一次请求都要创建一个实例,对于“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。
为什么不能用二级缓存或者一级缓存解决循环依赖?
如果是一级缓存,那么一个map里面肯定有已经完成初始化了的Bean和实例化了但是还没有完成属性注入的Bean,此时其他需要来这里获取Bean时可能会拿到还没有属性注入的Bean,会导致抛空指针异常,所以一级缓存是不行的。
其实二级缓存也是可以解决循环依赖的,但是为了方便用户自己拓展,所以运用了三级缓存,
关于为什么不用二级缓存,建议阅读–》》》https://www.cnblogs.com/grey-wolf/p/13034371.html