本文根据Spring源码分析Spring中如何处理循环引用。
循环引用即A-B-A引用问题,关键在于如何解决创建A需要B,创建B需要A的问题,Spring中采用暴露未完成的Bean的方法实现循环引用。
tips:该方法并不能解决所有的循环引用问题,如构造器内的循环应用就无法解决。
Spring中包含三级缓存,这三级缓存在DefaultSingletonBeanRegistry中,是三个以BeanName为key的map
/** 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 ConcurrentHashMap<>(16);
缓存的查找过程在getSingleton方法中
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 先找一级缓存
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 找二级缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
// 双重检查
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 根据工厂获取Bean
singletonObject = singletonFactory.getObject();
// 加入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 从三级缓存中删除
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
完成实例化后,会将一个工厂放入三级缓存,只有存工厂才能获得代理对象
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
...
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 单例、允许循环引用、正在被创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 添加到三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
}
此时如果产生循环依赖,会再次进入缓存查找过程,此时会找到缓存的A的工厂,根据工厂生产未完成的A,加入二级缓存,删除三级缓存中的A工厂,并返回未完成的A。