循环依赖的产生

循环依赖的情况

  1. A的构造方法中依赖B的实例,B的构造方法中依赖A的实例
  2. A的构造方法中依赖B的实例,B的某个属性或者set方法需要A的实例
  3. A的某个属性或者set方法依赖B的实例,B的某个属性或者set方法依赖A的实例

spring 解决循环依赖也有条件限制。首先bean是单例,并且没有指定不需要解决循环依赖。如果两个bean是构造器循环依赖也无法解决。

spring解决循环依赖原理

首先看下spring创建单例对象的步骤:

  1. createBeanInstance 创建bean实例,只是调用了构造方法
  2. populateBean 给创建好的bean实例填充属性
  3. initializeBean 调用各种Processor,或者init方法等初始化bean

循环依赖发生在步骤1,2中

三个缓存

spring 使用三个缓存解决了单例的循环依赖问题

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

singletonObjects:缓存单例对象
singletonFactories:缓存单例对象的工厂
earlySingletonObjects:缓存提前曝光的单例对象

spring bean创建过程

在AbstractBeanFactory的doGetBean方法创建bean的过程中,首先会调用getSingleton(beanName) 方法,尝试从3个缓存获取单例bean。

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 != NULL_OBJECT ? singletonObject : null);

首先从singletonObjects缓存中尝试获取bean对象,如果取不到,从earlySingletonObjects中获取,如果还获取不到从singletonFactory通过getObject获取。如果获取到则移除对应的singletonFactory,将单例对象放到earlySingletonObjects.

spring 解决循环依赖在于singletonFactories

AbstractBeanFactory的doGetBean方法创建bean的代码:

// Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							try {
								return createBean(beanName, mbd, args);
							}
							catch (BeansException ex) {
								// Explicitly remove instance from singleton cache: It might have been put there
								// eagerly by the creation process, to allow for circular reference resolution.
								// Also remove any beans that received a temporary reference to the bean.
								destroySingleton(beanName);
								throw ex;
							}
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

1.将bean实例加入singletonObjects
2.从singletonFactories中移除ObjectFactory

AbstractAutowireCapableBeanFactory 中doCreateBean的方法, bean刚通过构造方法创建成功,新建一个匿名ObjectFactory 加入singletonFactories 缓存中

if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

1.将ObjectFactory加入singletonFactories
2.将刚通过构造器创建好的bean (还未进行初始化的2个步骤)提前曝光,可以让别的bean引用

循环依赖情况3分析:
1.创建A单例对象,首先尝试从3个缓存中获取该名字的单例bean,没有获取到通过构造方法创建A单例bean,将A单例对象加入到singletonFactories 缓存中
2.A单例对象填充属性,注入B单例对象。通过getBean 方法创建获取B单例对象,尝试从缓存中获取B单例对象,没有获取到,通过构造方法创建B单例bean,将B单例对象加入到singletonFactories缓存中。
3.B单例对象填充属性,注入A单例对象,在singletonFactories缓存中找到该bean的ObjectFactory 获取A单例对象。B单例对象继续填充属性,初始化至创建完成,将自己放入singletonObjects缓存中。
4.A单例获取到B单例对象完成属性注入,继续执行创建步骤,最终将自己放入singletonObjects缓存中。

B持有A的引用,所以B持有的A对象是最新的。

参考:
Spring源码初探-IOC(4)-Bean的初始化-循环依赖的解决