什么是循环依赖?
存在类A实例Bean、类B实例Bean、类C实例Bean,在类A中引用了类B,类B中引用了类C,同时类C中引用了类A,此时使用Spring初始化类A、B、C便会存在循环引用的情况。当实例化A时发现其引用了B实例;于时对B进行实例化,实例化B时又对C实例进行引用;于时再实例化C,实例化C时,又引用了A实例,而此时A还在等待B初始化完成,因此出现死循环的现象。
在Spring中解决循环引用的方式是使用三级缓存策略,分别如下
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
单例模式下,第一次获取Bean时由于Bean示例还未实例化,因此会先创建Bean然后放入缓存中,以后再次调用获取Bean方法将直接从缓存中获取,不再重新创建。Spring中,获取Bean的流程:
缓存添加过程主要发生在创建Bean也就是doCreateBean()过程中。doCreateBean()中有这样一句代码
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
其源码如下
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主要经历了一下三个过程:
从代码中可以看到在这里将beanName放入三级缓存中,并且从二级缓存中移除。这里的addSingletonFactory发生在createBeanInstance之后,此时已经有了实例对象,但是还没创建完成便放入三级缓存当中。在doCreateBean()方法执行完成之后,Bean实例创建完成,因此在第二个getSingleton()中的finally块中如果是新的单例对象则会调用addSingleton()方法。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
可以看到此时将加入一级缓存中,并且从二级、三级缓存中移除。
缓存的获取是通过getSingleton(String beanName)方法获取的,其源码如下:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
在代码中,首先从一级缓存singletonObjects中获取Bean;如果获取不到并且获取的Bean被标记为正在创建中,则从二级缓存earlySingletonObjects中获取;如果二级缓存中依然获取不到Bean,并且允许从三级换从中获取Bean,则从三级缓存中获取Bean,此时如果获取到了Bean,则将该Bean从三级缓存中移除,然后添加进二级缓存(缓存升级),否则返回null。
通过使用三级缓存可以解决循环依赖的问题,以A、B、C相互依赖的情况为例,其解决循环依赖流程如下:
Spring源码分析——Bean创建
Spring源码分析——获取Bean
Spring源码分析——解决循环依赖