【Spring】DI:循环依赖 singleton 三层缓存

时间:2021-2-26 作者:admin

singleton 三层缓存

/** Cache of singleton objects: bean name to bean instance. */
/** 一级 cache,缓存的是成品单例对象 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of early singleton objects: bean name to bean instance. */
/** 二级 cache,缓存半成品单例对象,且该半成品被引用了 */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

/** Cache of singleton factories: bean name to ObjectFactory. */
/** 三级 cache,缓存半成品单例对象,但该半成品未被引用  */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

doGetBean 里的两种 getSingleton()

doGetBean 一进去调用的:

【Spring】DI:循环依赖 singleton 三层缓存

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  
  // 尝试从缓存中获取成品的目标对象,如果存在,则直接返回
  Object singletonObject = this.singletonObjects.get(beanName);
  
  // 如果缓存中不存在目标对象,则判断当前对象是否已经处于创建过程中,在前面的讲解中,第一次尝试获取A对象
  // 的实例之后,就会将A对象标记为正在创建中,因而最后再尝试获取A对象的时候,这里的if判断就会为true
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    synchronized (this.singletonObjects) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
        
        // 这里的singletonFactories是一个Map,其key是bean的名称,而值是一个ObjectFactory类型的
        // 对象,这里对于A和B而言,调用图其getObject()方法返回的就是A和B对象的实例,无论是否是半成品
        ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
        if (singletonFactory != null) {
          
          // 获取目标对象的实例
          singletonObject = singletonFactory.getObject();
          this.earlySingletonObjects.put(beanName, singletonObject);
          this.singletonFactories.remove(beanName);
        }
      }
    }
  }
  return singletonObject;
}

上一个 getSingleton 返回值为 null,并且 beanDefition 为 singleton 的作用域时调用

【Spring】DI:循环依赖 singleton 三层缓存

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    // 加锁
    synchronized (this.singletonObjects) {
        // 检查 singletonObjects 缓存中是否有
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // 检查是否在执行销毁
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                        "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            // 将 Bean 添加到 singletonsCurrentlyInCreation 集合中, 表示正在创建
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // 调用工厂方法
                // 也就是调用 createBean(beanName, mbd, args)
                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;
                }
                // 创建成功, 从 singletonsCurrentlyInCreation 移除
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                // 将给定的单例对象添加到该工厂的单例缓存中
                //     this.singletonObjects.put(beanName, singletonObject);
                //     this.singletonFactories.remove(beanName);
                //     this.earlySingletonObjects.remove(beanName);
                //     this.registeredSingletons.add(beanName);
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

doCretaeBean 里放入 singletonFactories

【Spring】DI:循环依赖 singleton 三层缓存

循环依赖总结

解决方法:singleton 家族,三层 cache

  • 第一层 singletonObjects(已经初始化完,成品 bean ,通过 getSingleton 的重载方法放入,该重载方法的入参是 beanName 和 ObjectFactory 的未实现方法 getObject,该 ObjectFactory 使用 lamda 形式创建,在其唯一的 getObject 方法中会调用 createBean 创建 bean,然后用 addSingleton 方法放入 singletonObjects )
  • 第二层 earlySingletonOjbects(半成品 bean,不会直接在某个步骤直接放入,在 doGetBean 方法一进去就调用的 getSingleton(beanName) 中,如果 singletonObjects 中没有,但是 singletonFactores 中有的话,会把 singletonFactories 中该半成品 bean 放入 earlySingleton ,代表未初始化完成但是被依赖)
  • 第三层 singletonFactoies (半成品 bean,在 docreateBean 的 createBeanInstance 完成后调用 addSingletonFactories 放入,也正是因为在这个时机放入,所以如果因为构造方法出现循环依赖无法解决,因为 createBeanInstance 最后会调用 SimpleInitalizeStagy 的 instant 方法,该方法在 beanDefition 不存在覆盖方法时就会用 JDK 的反射创建对象,创建的方法就是获得 constructor 然后 newInstance,所以如果在解析 constructor 的参数有循环依赖,那么当前的半成品还未放入 singletonFactoies)
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。