循环依赖的原文是circular reference,指多个对象相互引用,形成一个闭环。
以两个对象的循环依赖为例:

Spring中的循环依赖有 3 种情况:
其中的第 2 、第 3 种情况Spring可以解决,但第 1 情况Spring无法解决。当出现构造器循环依赖的时候,会抛出异常:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘cat‘ defined in class path resource [constructor.xml]: Cannot resolve reference to bean ‘dog‘ while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ‘dog‘: Requested bean is currently in creation: Is there an unresolvable circular reference?
或
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
|  securityConfig defined in file [E:\IDEA\lab-back-end\target\classes\com\lpc\config\SecurityConfig.class]
↑     ↓
|  userServiceImpl defined in file [E:\IDEA\lab-back-end\target\classes\com\lpc\service\impl\UserServiceImpl.class]
└─────┘
准备两个POJO
public class Dog {
    private String name;
    private Cat friend;
    public Dog() {
    }
    public Dog(String name, Cat friend) {
        this.name = name;
        this.friend = friend;
    }
    // 省略getter、setter
}
public class Cat {
	private String name;
	private Dog friend;
	public Cat() {
	}
	public Cat(String name, Dog friend) {
		this.name = name;
		this.friend = friend;
	}
	// 省略getter、setter
}
Cat类里有个成员变量的类型是Dog类,同时Dog类里有个成员变量的类型是Cat类,满足了循环依赖的条件。
准备一个field.xml,这个xml配置了两个bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="dog" class="Dog">
		<property name="name" value="dog"/>
		<property name="friend" ref="cat"/>
	</bean>
	<bean id="cat" class="Cat">
		<property name="name" value="cat"/>
		<property name="friend" ref="dog"/>
	</bean>
</beans>
xml里声明了两个bean,通过属性注入的方式将另一个bean引用到自己的成员变量中。在主类中加载xml:
ClassPathXmlApplicationContext ac
      = new ClassPathXmlApplicationContext("field.xml");

方法调用过程总结可以直接跳转到3.12。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    // 省略部分代码
	Object bean;
	// 重要步骤
	// 检查单例缓存中是否有手动注册单例bean
	// 它其实是调了DefaultSingletonBeanRegistry#getSingleton(beanName, true)
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		// 省略部分代码
	}
	else {
		// 省略部分代码
        try {
			// 省略部分代码
            if (mbd.isSingleton()) {
                // 重要步骤
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        // 重要步骤
                        // singletonFactory.getObject()的具体实现。AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])
                        return createBean(beanName, mbd, args);
                    }
                    // 省略部分代码
                });
                // 省略部分代码
            }
            // 省略部分代码
    }
    // 省略部分代码
    return (T) bean;
}
这里有两段代码是重点。
Object sharedInstance = getSingleton(beanName);
这个方法调用的实际上是getSingleton(beanName, true);。详见3.4。
sharedInstance = getSingleton(beanName, () -> {
    try {
        // 重要步骤
        // singletonFactory.getObject()的具体实现。AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])
        return createBean(beanName, mbd, args);
    }
    // 省略部分代码
});
详见3.5。
DefaultSingletonBeanRegistry类的三个Map类型的成员变量,这三个成员变量也就是所谓的三级缓存。
// 一级缓存
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);
// 除了三级缓存以外,还有一个Set,beanName保存在这个Set里表示这个bean正在创建中
private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// 三级缓存其实就是三个Map,键是beanName
	// 1 去一级缓存singletonObjects里获取
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		// 如果 没有从一级缓存中获取到,且对象在正在创建中
        // 判断对象正在创建中的方法是判断beanName是不是在singletonCurrentlyInCreation这个Set里
		synchronized (this.singletonObjects) {
			// 2 从二级缓存earlySingletonObjects中获取
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				// 如果 二级缓存中没有获取到,且allowEarlyReference为true
				// 3.1 从三级缓存中获取,这时候获取到的是ObjectFactory,这是个工厂,并不是我们要实例
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					// 3.2 从对象工厂中获取实例
					singletonObject = singletonFactory.getObject();
					// 3.3 将获取到的实例保存到二级缓存(为什么不用保存到一级缓存)
					this.earlySingletonObjects.put(beanName, singletonObject);
					// 3.4 将工厂从三级缓存中移除
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}
3.5其实是3.4的重载。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		// 省略部分代码
		synchronized (this.singletonObjects) {
		// 去一级缓存中拿bean
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			// 省略部分代码
			// 重要步骤
			// 这个方法会将beanName添加到singletonsCurrentlyInCreation这个Set中
			// 这步添加操作会在后面调用getSingletion(String, boolean)的时候起作用
			beforeSingletonCreation(beanName);
			
			// 省略部分代码
			try {
				// 重要步骤
				// 在这一步创建了对象
				// singletonFactory是作为参数传进来的匿名内部类
				singletonObject = singletonFactory.getObject();
				// 省略部分代码
			} 
			// 省略部分代码
		}
		return singletonObject;
	}
}
这里有两段代码是重点。
beforeSingletonCreation(beanName);
这个方法会将beanName添加到singletonsCurrentlyInCreation这个Set中。方法见3.6。singletonsCurrentlyInCreation的定义见3.4。
singletonObject = singletonFactory.getObject();
singletonFactory是方法的参数,实际上是3.3第二段重要代码中用lambda创建的匿名内部类,实际上调用的是AbstractAutowireCapableBeanFactory类的doCreateBean(String, RootBeanDefinition, jObject[])
protected void beforeSingletonCreation(String beanName) {
   // inCreationCheckExclusions singletonsCurrentlyInCreation都是Set
   // 这里在做判断的同时,调用了Set的add()方法
   // 所以beanName被添加到了singletonsCurrentlyInCreation中
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
	BeanWrapper instanceWrapper = null;
	// 省略部分代码
	if (instanceWrapper == null) {
		// 重要步骤
		// 在这里调用合适的构造方法生成实例,并将实例放在一个包装类中。这里就不详细展开了
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	// 从包装类中将实例取出来
	final Object bean = instanceWrapper.getWrappedInstance();
	// 省略部分代码
	// 这个boolean值的结果取决于->单例、allowCircularReferences为true(默认就是true)、对象正在创建中
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		// 省略部分代码
		// 重要步骤
		// 这个方法里会将bean添加到三级缓存中
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
		// 重要步骤
		// 给属性赋值
		populateBean(beanName, mbd, instanceWrapper);
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	} 
	// 省略部分代码
}
这里有三段重要代码:
instanceWrapper = createBeanInstance(beanName, mbd, args);
这个方法选择了合适的构造函数来构建实例。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
在这个方法里将beanName和beanFactory放到了三级缓存中。详见3.8。
populateBean(beanName, mbd, instanceWrapper);
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      if (!this.singletonObjects.containsKey(beanName)) {
         // 如果 一级缓存中还没有这个beanName
         // 在三级缓存中做一下保存
         this.singletonFactories.put(beanName, singletonFactory);
         // 在二级缓存中移除
         this.earlySingletonObjects.remove(beanName);
         // 在registeredSingletons里添加
         this.registeredSingletons.add(beanName);
      }
   }
}
在这个方法里将beanName和beanFactory放到了三级缓存中。这时候,三级缓存里面已经有我要创建的dog对象(其实是有了创建这个对象的工厂)。
这个方法调用了AbstractAutowireCapableBeanFactory类applyPropertyValues()方法,applyPropertyValues()方法又调用了BeanDefinitionValueResolver类resolveReference()方法。最后又调用了doGetBean(),也就是3.3的方法。
doGetBean()在这里是为了给dog对象创建它的Cat类成员变量。
在DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>)方法中,还调用了addSingleton(beanName, singletonObject);,这个方法会将bean添加到第一级缓存中,并从第二、第三级缓存中移除。当然这一步跟解决循环依赖没有关系。
总结一下整个过程:
总的来说,Spring是依靠第三级缓存解决了循环依赖的问题,通过递归创建当前bean依赖的bean。
本文由博客群发一文多发等运营工具平台 OpenWrite 发布
原文:https://www.cnblogs.com/FatShallot/p/12784690.html