spring中存在三种循环依赖:
BeanCurrentlylnCreationException
异常spring 单例对象的实例化、初始化过程是在doCreateBean
中(之前仅仅是注册好了BeanDefenition), 大概分为三步:
postProcessBeforeInitialization->init->postProcessAfterInitialization
)this.singletonsCurrentlylnCreation.add(beanName
将当前正要创建的bean 记录在缓存中
Spring 容器将每一个正在创建的bean 标识符放在一个”当前创建 bean 池”中,在创建过程中将一直保持在这个池中,因此如果在创建bean 过程中发现自己已经在”当前创建bean 池” 里时,将抛出BeanCurrentlylnCreationException
异常表示循环依赖;而对于创建完毕的bean 将从”当前创建bean 池”中清除掉
spring 使用三级缓存来解决单例 setter 循环依赖:
private final Map singletonObjects = new ConcurrentHashMap(256);
private final Map> singletonFactories = new HashMap>(16);
private final Map earlySingletonObjects = new HashMap(16);
我们在创建bean的时候,会首先从cache中获取这个bean,这个缓存就是sigletonObjects。主要的调用方法是:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
//isSingletonCurrentlyInCreation()判断当前单例bean是否正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从二级缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
// allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//从singletonFactories中移除,并放入earlySingletonObjects中。
//其实也就是从三级缓存移动到了二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
结合 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, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// addSingletonFactory
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 放入singletonFactories
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
// bean 可以通过 SmartInstantiationAwareBeanPostProcessor 进行扩展
// 所以采用了三级缓存而不是两级缓存
// 这里参考 https://blog.csdn.net/weixin_42228338/article/details/97163101
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;
}
addSingletonFactory
这段代码发生在createBeanInstance
之后,populateBean
之前,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,此时将这个对象提前曝光出来,让大家使用。
举例说明一下这样做的用意,假如A依赖了B, B也同时依赖于A:
singletonFactories
中,此时进行初始化的第二步(populateBean填充属性),发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create
,所以走create流程这样就是整个解决 setter 循环依赖的过程
代码也在创建bean的时候体现:
// 创建过了此 beanName 的 prototype 类型的 bean,那么抛异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}