一、什么是循环依赖
循环依赖就是对象之间互相引用或者自引用,循环引用会导致一个现象,例如,A,B对象之间互相引用,创建A对象的时候会对属性B进行注入,从而触发B对象的实例化,而对B对象设置A属性的时候又会触发A对象的创建,出现循环创建的现象。
这个问题其实很好解决,加缓存,对象创建后先缓存再进行属性注入,如果出现循环依赖直接使用缓存的对象注入即可
看上去这个问题就解决了,但是我们知道Spring AOP是在对象创建后的后置处理器中完成的,这就会出现一种情况如下图
![5913a6ffeffbadd53c4023e88ab9b277.png](https://img-blog.csdnimg.cn/img_convert/5913a6ffeffbadd53c4023e88ab9b277.png)
可以看到B注入的是原始的A对象,而不是增强后的代理对象,这会导至AOP失效,这显然不是我们想要的结果
这个问题又该怎么解决呢?看看Spring是怎么解决的。
二、spring的三级缓存
2.1 先看看Bean的初始化流程
![90375d5a6cca24bc0bc00dc4cd7b3f08.png](https://img-blog.csdnimg.cn/img_convert/90375d5a6cca24bc0bc00dc4cd7b3f08.png)
可以看到进行了好几次缓存的操作,这个就是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
:完全初始化好的单例对象(一级缓存)earlySingletonObjects
:提前曝光的单例对象,完成实例化但是没有填充属性和初始化(二级缓存)singletonFactories
:在 bean 实例化完之后,属性填充以及初始化之前,如果允许提前曝光,Spring 会将实例化后的 bean 提前曝光,也就是把该 bean 转换成beanFactory
并加入到singletonFactories
(三级缓存)
2.2 Spring的解决方案
先从缓存获取bean
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//1. 先从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//2. 一级缓存没有,查找二级缓存
singletonObject = this.earlySingletonObjects.get(beanName);
//2. 二级缓存也没有,查找三级缓存
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//4.三级缓存存在,使用工厂创建对象,并移动到二级缓存
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
如果缓存不存在,创建对象
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
//1.调用createBean创建对象
singletonObject = singletonFactory.getObject();
addSingleton(beanName, singletonObject);
//2.将初始化完成的对象放入一级缓存
return singletonObject;
}
}
对象创建完成后,会先将工厂对象添加到三级缓存,再进行属性的设置
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
instanceWrapper = createBeanInstance(beanName, mbd, args);
final Object bean = instanceWrapper.getWrappedInstance();
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
//1.如果需要提前暴露(支持循环依赖),就注册一个ObjectFactory到三级缓存
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
//2.设置属性,如果触发循环依赖,getEarlyBeanReference创建代理
populateBean(beanName, mbd, instanceWrapper);
//3.如果已经创建了代理,initializeBean就不会再重复创建了
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
if (earlySingletonExposure) {
//4.如果触发了循环依赖,那么exposedObject还是原始对象,代理对象此时在二级缓存,将exposedObject赋值为代理对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
}
}
return exposedObject;
}
如果出现循环依赖就会先从三级缓存获取工厂对象,再通过工厂对象来获取实际的bean对象,可以看到如果没有配置后置处理器,那么返回的就是原始对象
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object 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;
}
如果配置了后置处理器,就会去生成代理对象
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
//生成代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
创建完成后,将bean添加到一级缓存,并删除二级缓存,三级缓存
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);
}
}
总结下,缓存的工作流程如下
![7e1ec38968978cc53bc0d396b51d77d2.png](https://img-blog.csdnimg.cn/img_convert/7e1ec38968978cc53bc0d396b51d77d2.png)
三、其他问题
需要注意的是上述循环依赖的解决方案的场景是单例模式set注入
其他作用域循环依赖
对于prototype
作用域的bean,每次请求都会创建一个实例对象,没有缓存,如果出现循环依赖会直接抛出异常,对于其他作用域虽然可以加缓存但是如果缓存太多会也会导致太复杂
构造器注入
循环依赖场景是无法解决的因为构造器进行属性注入的时候,因为对象还没有创建完成,也就不能就行提前暴露操作