spring源码阅读(4)IOC与循环依赖

Posted by New Boy on February 9, 2020

前言

关于spring解决循环依赖的问题,在之前第二篇讲Bean的实例化与初始化的时候,有3个地方提到过循环依赖的问题,可以来看看这3个地方是怎么实现的

获取提前暴露的Bean

在AbstractBeanFactory#doGetBean方法中的第一步,就是尝试从缓存中拿到bean,

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		} else {
		//.....创建新的bean
    }
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
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;
	}

这里的逻辑是这样的:

1.先尝试从singletonObjects中获取bean对象,如果已经存在该单例bean,则直接返回

2.再尝试从earlySingletonObjects中找bean对象,如果可以找到,变直接返回

3.如果earlySingletonObjects中还没有,则从singletonFactories中获取,如果能找到ObjectFactory,则调用ObjectFactory的getObject的方法,生成对象,放入earlySingletonObjects,并删除对应的BeanFactory

可以看到,这里是有3个缓存,singletonObjects比较清楚,就是用来存放单例的,earlySingletonObjects和singletonFactories又是在什么时候处理的呢?

将bean提前暴露

一层层深入,到了AbstractAutowireCapableBeanFactory#doCreateBean方法中

// bean的实例化
BeanWrapper instanceWrapper = null;
instanceWrapper = createBeanInstance(beanName, mbd, args);
//....

//在进入该方法前,会先将beanName放入singletonsCurrentlyInCreation中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                  isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
  addSingletonFactory(beanName, (beanName, mbd, bean) -> {
    Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
  });
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
  synchronized (this.singletonObjects) {
    if (!this.singletonObjects.containsKey(beanName)) {
      this.singletonFactories.put(beanName, singletonFactory);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
    }
  }
}

至此,也就可以说通了,在实例化完成之后,初始化之前,如果可以判定某个bean正处在创建中,那边就会生成一个ObjectFactory,放入singletonFactories中,下次就会直接根据ObjectFactory这个三级缓存直接返回对象。

当然,这里我们还看到了SmartInstantiationAwareBeanPostProcessor这种BeanPostProcessor,这种BeanPostProcessor的具体的用处还真是不太清楚,但从代码中可以推断出来,如果要对提前暴露的Bean做个处理(还未初始化),则可以通过这种处理器

总结

举个简单的例子:

A和B互相依赖

  1. getBean(A)
  2. addSingletonFactory(A)
  3. getBean(B)
  4. addSingletonFactory(B)
  5. getBean(A)
  6. singletonFactories.get(A).getObject(),返回已经提前实例好但为初始化的Bean实例