Spring Bean 循环依赖解决简单分析
本文Spring版本:
5.0.5.RELEASE
什么是循环依赖:
循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A 依赖 B,B 又依赖 A;或者A依赖于B,B依赖于C,C又依赖于A。
Spring 循环依赖的处理方式:
①构造器的循环依赖:这种依赖spring是处理不了的,直 接抛出BeanCurrentlylnCreationException异常。
②单例模式下的setter循环依赖:通过“三级缓存”处理循环依赖。
③非单例循环依赖:无法处理。
Spring 如何解决单例Bean的循环依赖问题?
利用三级缓存(DefaultSingletonBeanRegistry中定义)。
singletonObjects |
用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用 |
earlySingletonObjects | 存放原始的 bean 对象(尚未填充属性) |
singletonFactories | 存放 bean对应的工厂对象(ObjectFactory) |
解决循环依赖加载bean的大致流程:
判断缓存中是否有X:
//DefaultSingletonBeanRegistry#getSingleton
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//singletonObjects 第一级缓存,BeanFactory的单例全存在singletonObjects中
//保存的是已经初始化完全的单例
Object singletonObject = this.singletonObjects.get(beanName);
//isSingletonCurrentlyInCreation=true,代表beanName所代表的bean循环依赖了
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//第二级缓存,保存的是未初始化完全的单例(只是实例化)
singletonObject = this.earlySingletonObjects.get(beanName);
//allowEarlyReference在当前场景下,默认为true
if (singletonObject == null && allowEarlyReference) {
//第三级缓存,不是真的缓存,缓存的是生成二级缓存的工厂方法
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//通过缓存singletonFactories中的对象工厂获取bean的对象
//如果有AOP,获取的会是代理对象
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
实例化bean之后,会把获取当前bean的方式放入到singletonFactories缓存:
注意:Map<String, ObjectFactory<?>> singletonFactories
该级缓存存放的并不是实例化的bean,而是一个ObjectFactory对象,它可以构造出对应的bean
//AbstractAutowireCapableBeanFactory#doCreateBean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
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);
}
});
}
当bean实例化完成之后,会被放到一级缓存singletonObjects中,用于被其他bean获取:
//DefaultSingletonBeanRegistry#getSingleton#addSingleton
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
为什么是三级缓存?
好像使用 earlySingletonObjects 和 singletonObjects 两级缓存,一个存放早期对象,一个存放初始化完成后的对象,也能实现同样的功能,singletonFactories 好像显得有些多此一举。其实不是的,对于普通对象,确实只要返回刚创建完的早期对象就好了,但对于内部有被 AOP 增强的方法的对象,需要返回的是代理对象。我们可以看一下 ObjectFactory 匿名内部类里面调用的 getEarlyBeanReference 方法:
//AbstractAutowireCapableBeanFactory
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// SmartInstantiationAwareBeanPostProcessor 这个后置处理器会在返回早期对象时
// 被调用,如果返回的对象需要加强,那这里就会生成代理对象
// 如果返回的对象需要AOP增强,那这里exposedObject 就会替换成代理对象的引用
// 比如上图中的bean X 如果被AOP增强,那么bean Y 加载时获取的bean X 其实是X的代理对象
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
我们可以看到对于一般的对象,返回的就是传入的早期对象,但是对于内部有被 AOP 增强的方法的对象,会使用后置处理器返回一个代理对象。
如果在解决循环依赖时生成了代理对象,那么 AbstractAutoProxyCreator 会把原对象放入一个 Map 中,这个 Map 的作用是防止同类对象被重复动态代理:
//AbstractAutoProxyCreator
public Object getEarlyBeanReference(Object bean, String beanName) {
// 提前暴露代理对象的引用,是在postProcessAfterInitialization之前执行
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
//AbstractAutoProxyCreator
//有些BeanPostProcessor提供对Bean的Wrap的操作,但是生命周期位于在set操作之后,避免重复代理
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
earlySingletonObjects作用是可以提升多次循环依赖加载的效率(singletonFactory.getObject() 不用多次执行),比如 X 依赖 Y, Y 依赖 X, Z 也依赖 X。Y 注入 X 时 earlySingletonObjects 已经通过 singletonFactory.getObject() 得到了原始X,这样加载Y时就不用再执行 singletonFactory.getObject() 构造 X 实例了,直接从earlySingletonObjects获取即可。