什么是循环依赖?
当一个Bean依赖于另一个Bean时,这个被依赖的Bean同样也依赖于第一个Bean,从而形成一个循环链。这种循环关系可能会导致初始化和依赖注入的问题,因为它们都依赖于同一个目标实例
比如: “A对象依赖B对象, 而B对象也依赖A对象”
A→B
B→A

此时,图中是一个闭环,如果想解决这个问题,那么就必须要保证不会出现第二次创建A对象这个步骤,也就是说从容器中获取A的时候必须要能够获取到
解决循环依赖? 提前暴露
实例化好单未完成初始化的对象是可以直接给其他对象引用的,所以此时可以做一件事,把完成实例化但未完成初始化的对象提前暴露出去,让其他对象能够进行引用,就完成了这个闭环的解环操作;
这也就是常规说的提前暴露对象
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
......
/**
* 判断当前: 是否单例 && 是否允许循环依赖 && 是否正在创建过程中
*/
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
/**
* 不管需不需要, 先放到三级缓存, 提前暴露出去
*/
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
......
}为什么需要三级缓存?
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
/** Cache of singleton objects: bean name to bean instance. */
/**
* 一级缓存 这是最终缓存实例的地方,保存完全初始化并准备好的Bean实例。
* 所属: org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
/**
* 三级缓存
* 里面存放的是将要被实例化的对象的对象工厂(存放 bean 工厂对象),是一个包裹对象`ObjectFactory(registeredSingletons)`,经过getObject获取到早期对象。
* 所属: org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonFactories
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
/**
* 二级缓存
* 存放早期暴露出来的Bean对象,实例化以后,就把对象放到这个Map中。(Bean可能只经过实例化,属性还未填充)
* 所属: org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#earlySingletonObjects
*/
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);第一级缓存: org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects 里面放置的是已经实例化 完整可用的 单例缓存池(singletonObjects)
第二级缓存: org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#earlySingletonObjects 里面存放的是提早曝光的单例对象,早期对象(earlySingletonObjects)。简单粗暴的说就是new的对象, 可是这个对象还没填充属性, 全部属性都是null
第三级缓存: org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonFactories 里面存放的是将要被实例化的对象的对象工厂(存放 bean 工厂对象),是一个包裹对象ObjectFactory(registeredSingletons),经过getObject获取到早期对象。
不是为解决循环依赖
正常来讲, 处理循环依赖, 类似交换变量 (temp约等于缓存), 只需要一级缓存即可;
function swap(a, b){
temp = a;
a = b;
b = temp;
}加上单例缓存池, 只需两级缓存
增加的第三级缓存
第三级缓存是处理 AOP 增强bean 的问题;
类似上面的例子, 解决 实例A 和 代理A , 保证只有一个能用的A对象
因为不知道 当前对象什么时候会被引用,是否需要被代理, 所以先把它 (bean 名称, bean实例 和 bean BeanDefinition 参数) 预变成一个lambda表达式 放在三级缓存中, 它有可能会被处理成AOP代理 对象 (在被引用的时候来判断对象是否需要被代理, 决定是否织入AOP)
例入: Aservice 依赖 Bservice 并且Bservice 依赖Aservice
- 创建Aservice时,实例化后, 将生成A的lambda放入三级缓存, 填充属性 Bservice,一二三级缓存中都没找到,
- 去创建Bservice,实例化后, 将生成B的lambda放入三级缓存, 填充Aservice属性,发现三级缓存中有A,执行A的lambda生成Aservice对象 (如果A需要被代理, 将在这里处理, 即: 不知道A是否需要动态代理, 在第一次引用的时候进行判断, 并处理它),并将A放入二级缓存(不能放一级这时候A的全部属性还是null),并删除A的三级缓存
- 继续执行B的 lambda 生成Bservice对象 (如果B也需要被代理, 将在这里处理) 将B放入一级缓存,并删除B的三级缓存; 此时: Bservice已完整可用, 且其AService属性是代理后的对象;
- 继续创建A的流程, 填充属性→ 初始化, 再从缓存中拿一次获取并替换(因为有可能A被代理了, 两次地址不一致就是被代理了, 参考下源码)
- 最后再将A (或者代理A)放入一级缓存中 代理A的对象属性是null, 它不需要, 持有原始对象A就行了
增强代理的相关源码
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
/**
* 1. 实例化
*/
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
/**
* 处理 MergedBeanDefinitionPostProcessor 的接口回调
*/
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.markAsPostProcessed();
}
}
/**
* 判断当前: 是否单例 && 是否允许循环依赖 && 是否正在创建过程中
*(循环依赖AOP) <!>
*/
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
/**
* 携带beanName,mbd 和原始bean示例 创建为 Lambda 表达式
*
* 放到三级缓存中
*
* <!> 循环依赖 AOP :这里其实还是会调用到 AutoProxyCreator 在其进行判断是否需要代理, 最终会调用到 createProxy 进行动态代理对象创建
* {@link org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference(java.lang.Object, java.lang.String)}
*/
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
/**
* 2.填充Bean属性
* 如果是AOP, pointcut, advice相关的会 调用 BeanPostProcessor 的子接口 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
* (作用是 在实例化之后,属性填充之前执行操作, 可以拦截属性填充操作)
*/
populateBean(beanName, mbd, instanceWrapper);
/**
* 3.初始化Bean对象
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
throw bce;
}
else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
}
}
if (earlySingletonExposure) {
/**
* (循环依赖AOP) 相关
* =======================
*/
/**
* 再从缓存中 再次获取并替换,是因为有可能是被代理
*/
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
/**
* (循环依赖AOP) <!>
* 注意: 这个bean是原始实例, 再从缓存中拿一次,是因为有可能是被代理(earlySingletonReference)
*/
if (exposedObject == bean) {
// 不一致就是被代理了
exposedObject = earlySingletonReference;
}
......