Spring 循环依赖

一、什么是循环依赖

注入的三种方式:

  • setter 方法进行注入

  • 构造方法进行赋值,但是这种情况不能实现循环依赖

  • field ( 反射,例如:@Autowired)

Spring 如何解决循环依赖:三级缓存

/** Cache of singleton objects: bean name to bean instance. */
// 用于存放完全初始化好的 bean 从该缓存中取出的 bean 可以直接使用 (单例Bean)
一级缓存: private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of early singleton objects: bean name to bean instance. */
// 存放原始的 bean 对象用于解决循环依赖,注意: 存到里面的对象还没有被填充属性,(半成品的 bean)
二级缓存: private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** Cache of singleton factories: bean name to ObjectFactory. */
// 存放 bean 工厂对象解决循环依赖
三级缓存: private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

循环依赖怎么解决 ( 看源码 )

1、首先进入 refresh() 方法,找到 其中的 finishBeanFactoryInitialization() 方法,并进入其中
// Instantiate all remaining (non-lazy-init) singletons.
// 创建所有剩余的非懒加载的单例类
// 剩余的单例对象: Spring 自己提供的(BeanPostProcessors),还有我们自己提供的(dao 层,service 层)
finishBeanFactoryInitialization(beanFactory);

2、找到 preInstantiateSingletons() 方法
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化单例对象之前要做的
beanFactory.preInstantiateSingletons();
// 在该方法中,会循环遍历所有的 beanName,里边会有三个熟悉的类,一个是Config, X, Y,执行顺序按顺序执行
for (String beanName : beanNames) {
  RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
  if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    if (isFactoryBean(beanName)) {
      Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
      if (bean instanceof FactoryBean) {
        final FactoryBean<?> factory = (FactoryBean<?>) bean;
        boolean isEagerInit;
        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
          isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                                      ((SmartFactoryBean<?>) factory)::isEagerInit,
                                                      getAccessControlContext());
        }
        else {
          isEagerInit = (factory instanceof SmartFactoryBean &&
                         ((SmartFactoryBean<?>) factory).isEagerInit());
        }
        if (isEagerInit) {
          getBean(beanName);
        }
      }
    }
    else {
      getBean(beanName);
    }
  }
}

在 for 循环中,会有一些判断

// bd 不是抽象的 且 这个 bd 是单例的 且 这个 bd 不是懒加载的 这个 if 判断才生效
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    // 如果是 FactoryBean,进入 if 判断,否则进入下边的 else
    if (isFactoryBean(beanName)) {
        // 如果是 FactoryBean 则加上 &
        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
        if (bean instanceof FactoryBean) {
            final FactoryBean<?> factory = (FactoryBean<?>) bean;
            boolean isEagerInit;
            if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                ((SmartFactoryBean<?>) factory)::isEagerInit,
                              getAccessControlContext());
            }
            else {
                isEagerInit = (factory instanceof SmartFactoryBean &&
                               ((SmartFactoryBean<?>) factory).isEagerInit());
            }
            if (isEagerInit) {
                getBean(beanName);
            }
        }
    }
    else {
        // 因为不是 FactoryBean,所以直接进入 getBean() 方法
        // 需要创建 X 对象,所以要判断工厂是否有该对象
        getBean(beanName);
    }
}

进入 getBean() 方法

@Override
public Object getBean(String name) throws BeansException {
    // 空壳方法
    return doGetBean(name, null, null, false);
}

进入空壳方法 doGetBean() 方法

// 找到改行代码
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
// 表示获取单例对象,但是到目前为止工厂中并没有该对象,所以此时 sharedInstance 为 null

// 进入这个方法
@Override
@Nullable
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

// 调用 getSingleton() 方法
Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 一级缓存 singletonObjects
    Object singletonObject = this.singletonObjects.get(beanName);
    // 第一次 isSingletonCurrentlyInCreation(beanName): 不成立,因为没有往里边的 set 集合存放内容
    // 第二次 isSingletonCurrentlyInCreation(beanName): 成立
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 二级缓存 earlySingletonObjects 
            singletonObject = this.earlySingletonObjects.get(beanName);
            // allowEarlyReference: 是否允许存放
            if (singletonObject == null && allowEarlyReference) {
                // 三级缓存 singletonFactories
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}
// 这里就开始涉及到三级缓存了
// 三个对象最主要的区别: 泛型不同,三级缓存存放的是 ObjectFactory 对象

// 执行完
Object sharedInstance = getSingleton(beanName);
// 获取到的 sharedInstance 的值为 null
// 那么接下来就会开始创建这个对象,一直到如下代码
if (!typeCheckOnly) {
    // 添加到 alreadyCreated set 集合中,表示已经创建过一次,防止重复创建
    markBeanAsCreated(beanName);
}
// 此时这个对象已经创建好了,仅仅只是个对象,因为里边的属性还没有填充好

// 继续往下走,直到遇到如下的注释
// Create bean instance.创建 bean 实例
// 这里要注意一下,这里的 getSingleton() 和刚才遇到的 getSingleton() 两个是不一样的
if (mbd.isSingleton()) {
    // 进入这个方法 createBean()
    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            // Also remove any beans that received a temporary reference to the bean.
            destroySingleton(beanName);
            throw ex;
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

进入 getSingleton() 方法

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
        // 调用一级缓存,但是此时是没有的
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName, "...");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            // 创建单例之前的回调
            // 这里将X对象标记为正在创建中,存放到 singletonsCurrentlyInCreation 集合中
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // 三级缓存
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}
// 这里有个问题: 一级缓存取不到,就去三级缓存中去取???而且三级缓存调用了一个方法 getObject()???
// 可以知道三级缓存的 value 值是 ObjectFactory 对象,这个对象中会有一个方法就是 getObject()
// 函数式接口,比如还有 Runnable 也实现了这个注解
@FunctionalInterface
public interface ObjectFactory<T> {
	T getObject() throws BeansException;
}
// 也就是说,这里调用 getObject() 方法的是 getSingleton() 方法的Lamda表达式
sharedInstance = getSingleton(beanName, () -> {
    try {
        return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
        // Explicitly remove instance from singleton cache: It might have been put there
        // eagerly by the creation process, to allow for circular reference resolution.
        // Also remove any beans that received a temporary reference to the bean.
        destroySingleton(beanName);
        throw ex;
    }
});

// 在调用 getObject() 方法的时,其实是执行的是,如下的代码
return createBean(beanName, mbd, args);

进入 createBean() 方法

// 找到如下的代码,这里调用 doCreateBean(),用来创建 bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);

// 进入 doCreateBean() 方法,看到如下的代码
if (instanceWrapper == null) {
    // 创建当前 bean 的实例
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 所以当 createBeanInstance() 这个方法执行完后,这个对象已经创建好了

// 继续向下执行
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) {
            // 判断一级缓存中是否包含 beanName,此时不包含,取反为 true,进入 if
            if (!this.singletonObjects.containsKey(beanName)) {
                // 将 beanName 以及 singletonFactory(匿名内部类) 存放到三级缓存
                this.singletonFactories.put(beanName, singletonFactory);
                // 二级缓存中什么也没有,移不移除无所谓
                this.earlySingletonObjects.remove(beanName);
                // 所有被创建的对象都会被放进去(只存 beanName)
                this.registeredSingletons.add(beanName);
            }
        }
    }

// 执行完返回继续执行,直到如下的代码
// 设置属性,非常重要
populateBean(beanName, mbd, instanceWrapper);
// 当执行完该方法后发现,X对象的属性Y已经被填充

// 细节可以进入该方法,找到如下代码
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);

// 进入 postProcessProperties() 方法,找到如下代码
metadata.inject(bean, beanName, pvs);

// 进入 inject() 方法,找到如下代码
element.inject(target, beanName, pvs);

// 进入 inject() 方法,找到如下代码
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

// 进入 resolveDependency() 方法,找到如下代码
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);

// 进入 doResolveDependency() 方法,找到如下代码
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);

// 进入 resolveCandidate() 方法,找到如下代码
return beanFactory.getBean(beanName);

// 进入 getBean() 方法,步骤与 x 一样
// 进入 doGetBean() 方法
// 进入 getSingleton() 方法,因为要调用两次该方法,第一次调用和 x 一样
// 再次进入 getSingleton() 方法
// 在进入该方法的匿名内部类,也就是如下代码
return createBean(beanName, mbd, args);
// 进入 createBean() 方法,找到如下代码
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
// 进入 doCreateBean() 方法,找到如下代码
instanceWrapper = createBeanInstance(beanName, mbd, args);
// 此时对象 Y 的 bean 实例已经被创建

// 继续往下执行
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 上一次执行该方法,是将 x 放到三级缓存
// 此时也一样,将 y 放到三级缓存

此时三个缓存状态如下图所示:

需要注意的是,三级缓存中存放了 X 和 Y 的匿名内部类,但是还没有执行

// 继续执行代码,该为 y 进行属性填充
populateBean(beanName, mbd, instanceWrapper);

// 进入该方法,找到如下代码
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// 或
applyPropertyValues() 方法(beanName, mbd, bw, pvs);
// 这两个有点区别: 当我们使用 @AUtowried 注解时,走 postProcessProperties() 方法,使用 xml 配置类时,使用 applyPropertyValues() 方法
// 由于我使用的是 @Autowired 注解,那么走上边那行代码

// 进入 postProcessProperties() 方法,我们需要对属性进行注入
metadata.inject(bean, beanName, pvs);

// 进入该方法
// 该方法使用循环的方式获取 X 中的属性,一次再调用 inject() 方法
element.inject(target, beanName, pvs);

// 该方法通过反射的方式获取到X中的属性
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
// 该 resolveDependency() 方法中文为解决依赖,我们可以看到其中的两个参数,一个是desc另一个是beanName,此时分别为: y, x

// 进入奥该方法中,找到如下代码
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);

// 进入奥该方法中,找到如下代码
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
// 代码如下
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException {
  return beanFactory.getBean(beanName);
}
// 中文翻译是解决候选者,就是解决X对象中的属性,这个属性没有,那么就创建一个
// 继续执行,一直到 getBean() 方法,但要注意此时 name 为 x,不是 y
// 进入 doGetBean() 方法,找到如下代码
Object sharedInstance = getSingleton(beanName);

// 进入该方法
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  // 一级缓存中找不到
  Object singletonObject = this.singletonObjects.get(beanName);
  // 这次这里成立,singletonObject 为空且X处于正在创建中,因此进入该 if 判断
  // return this.singletonsCurrentlyInCreation.contains(beanName);
  // singletonsCurrentlyInCreation 集合当中有 X 和 Y
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    synchronized (this.singletonObjects) {
      // 由于二级缓存中没有值,所以为 null
      singletonObject = this.earlySingletonObjects.get(beanName);
      // 二级缓存中没有值,且 allowEarlyReference 为 true 固定值
      if (singletonObject == null && allowEarlyReference) {
        // 调用三级缓存中的匿名内部类
        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
        if (singletonFactory != null) {
          // 执行Lamda表达式
          singletonObject = singletonFactory.getObject();
          // 存放到二级缓存中,暴露一个工厂(也可以说是半成品)
          this.earlySingletonObjects.put(beanName, singletonObject);
          // 删除三级缓存中对应的值
          this.singletonFactories.remove(beanName);
        }
      }
    }
  }
  return singletonObject;
}

// 继续执行一直到如下代码所示,执行第二个 getSingleton() 方法
sharedInstance = getSingleton(beanName, () -> {
    return createBean(beanName, mbd, args);
});

// 当该方法的 beforeSingletonCreation() 方法执行完后,说明:
beforeSingletonCreation(beanName);
// ***********************************************************
// *** 此时 X 和 Y 的状态是实例化完成,但还没有初始化,表示正在创建中 ***
// ***********************************************************
// singletonsCurrentlyInCreation 集合中存在 x 和 y

// 继续执行执行到如下所示时,进入 getObject() 方法
singletonObject = singletonFactory.getObject();

// 其实是调用了下行代码的 getEarlyBeanReference() 方法
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, 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;
}

// 注意: 这里要注意,什么时候才会需要进入 if 判断
// 上边的代码中,if 判断的部分是一个后置处理器,相当于说这部分是程序员可以对代码进行扩展的地方,如果不扩展,那么可以注释掉,Spring 自己也会对他做一个扩展

此时三个缓存状态如下图所示:

// 当执行完饭回到如下代码时
Object sharedInstance = getSingleton(beanName);
// 此时 sharedInstance 是有值的,X对象第一次调用该方法时,sharedInstance 为 null

// 因此如下的 if 条件是满足的,进入 if
if (sharedInstance != null && args == null) {
  if (logger.isTraceEnabled()) {
    if (isSingletonCurrentlyInCreation(beanName)) {
      logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                   "' that is not fully initialized yet - a consequence of a circular reference");
    }
    else {
      logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
    }
  }
  bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

// 继续往下执行,直到如下代码
return (T) bean;
// 将获取到的x对象返回,此时x完成实例化但还没有初始化完成

// 一路返回到 Y 对象所对应的 doGetBean() 中的第二个 getSingleton() 方法
addSingleton(beanName, singletonObject);
// 进入 addSingleton() 方法,将Y对象放到一级缓存中,此时Y即完成实例化也完成初始化
protected void addSingleton(String beanName, Object singletonObject) {
  synchronized (this.singletonObjects) {
    // 将Y对象添加到一级缓存
    this.singletonObjects.put(beanName, singletonObject);
    // 删除三级缓存中的Y对象
    this.singletonFactories.remove(beanName);
    // 删除二级缓存中的Y对象
    this.earlySingletonObjects.remove(beanName);
    this.registeredSingletons.add(beanName);
  }
}
// 执行完后返回到 doGetBean() 方法
// 此时Y对象创建完成,X对象还没有创建完成

此时三个缓存状态如下图所示:

// 继续执行代码,一路返回到 X 对象所对应的 doGetBean() 中的第二个 getSingleton() 方法
addSingleton(beanName, singletonObject);
// 将 X 对象添加到一级缓存中

此时三个缓存状态如下图所示:

// 此时 X 和 Y 都完成了实例化和初始化,并且放在了一级缓存中

// X 对象就创建成功了,一路返回到最开始的那个循环,此时该循环 Y
// 执行 getBean() 方法,在执行 doGetBean() 方法
// 在执行到 doGetBean() 方法中的 getSingleton() 方法中
// 现在一级缓存中去找,但是此时一级缓存中已经有 Y 对象了,所以不再需要取寻找,直接返回即可

问题:

1、为什么构造方法注入属性不能解决循环依赖?
// 答: Spring 解决循环依赖依靠的是 Bean 的 "中间态" 这个概念,而这个中间态指的是已经实例化,但还没完成初始化的状态。而构造器是需要完成实例化对象,所以构造器无法解决循环依赖
  
2、使用二级缓存能不能解决循环依赖?
// 答: 是可以的,三级缓存中存放的是 ObjectFactory 对象,为什么要存放这个对象,循环依赖中,这个对象存储的是一个 Lamda 表达式,这个表达式调用了 getEarlyBeanReference() 方法,这个方法中我们可以看到如果不执行 if 判断,那么传进来什么值,就返回什么值,问题就在于这个 if 做了什么,SmartInstantiationAwareBeanPostProcessor 是一个后置处理器,这个处理器用来创建代理类对象,假如我们生成一个代理类 AOP,比如 X 实现了 AOP,那么注入到其他 bean 的时候,得到的对象不是最终的代理对象,而是原始对象(通过上下文我们可以得到这个 bean 此时的状态还在实例化过程中)。就是说下面的代码的返回值表示三级缓存中的 value,如果只有二级缓存,那么只能获得原始对象,而不是代理对象
// 说简单点就是三级缓存中存放的 value 值是 ObjectFactory 对象,这个对象可能是普通的实例对象,也可能是普通实例对象的代理对象,如果不涉及到 AOP,那么使用二级缓存那么程序可以执行,不涉及到 AOP 那么不会走下面代码的 if 判断,但是如果涉及到 AOP,那么就需要的是代理对象,所以二级缓存是不可以的
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;
}
// 进入 getEarlyBeanReference() 方法
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
  Object cacheKey = getCacheKey(bean.getClass(), beanName);
  if (!this.earlyProxyReferences.contains(cacheKey)) {
    this.earlyProxyReferences.add(cacheKey);
  }
  return wrapIfNecessary(bean, beanName, cacheKey);
}
// 进入 wrapIfNecessary() 方法,找到如下代码
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
// 将我们给定的对象生成一个代理
// 此时 exposedObject 将变成生成的代理,而不是原先的原始对象

有兴趣的同学可以关注我的个人公众号,期待我们共同进步!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值