Spring中的循环依赖

循环依赖

  Spring使用依赖注入(DI)来实现控制反转(IoC),因而不可避免的会存在循环依赖的情况:当容器中的多个bean互相引用形成闭环的时候,就出现了循环依赖。

  // 创建A时需要B的实例,创建B时也需要A的实例,循环依赖产生

  @Component
  class A {
    @Autowired
    B b;
  }

  @Component
  class B {
    @Autowired
    A a;
  }

Spring中,依赖注入又可细分为构造函数注入和setter注入,相应地循环依赖的产生也有多种情况:

  1. A的构造函数依赖B,B的构造函数也依赖A

  2. A的构造函数依赖B,B持有一个A类型的属性,反之亦然

  3. A持有一个B类型的属性,B也持有一个A类型的属性

如何解决

  Spring使用缓存来解决循环依赖,创建bean时不等它完全初始化就提早暴露到缓存中,后续bean在创建过程中如果需要依赖其它bean则优先从缓存中获取(即使此时获取到的bean不是完全可用的状态)。这种策略其实是基于Java的引用传递,当我们获取到对象的引用时,对象的属性是可以延后设置的(但引用产生的前提是调用了构造函数)。

  很明显,在这种策略下前文提到的第一种情况是无法解决的,后两种情况则是有条件的解决。为什么说是有条件的解决呢?我们知道,Spring容器中的bean存在scope的概念,prototype类型的bean不会被缓存,每次请求都会重新创建一个,而singleton类型的bean在整个容器中有且仅有一个,理所应当会被缓存,因而仅有singleton类型的bean在产生循环依赖时能够得到解决。

如何实现

  了解了循环依赖产生的原因和Spring解决循环依赖的策略,接下来让我们一起探究一下在Spring 5.0.15.RELEASE中是如何实现的。

  不管是构造函数注入还是setter注入,首先要从容器中获取到对应bean实例,这部分逻辑在org.springframework.beans.factory.support.AbstractBeanFactory中:

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    @Override
    public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args, false);
    }

可以看到,重载的getBean(...)最后都代理给了doGetBean(...)

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        // 转换bean name,比如传入的是bean的别名,那么要通过别名获取到真正的bean name
        final String beanName = transformedBeanName(name);
        Object bean;
        
    // 重点:检查缓存或者创建对象的工厂中是否有对应的实例
    // 也正是在这里使用了三级缓存来解决循环依赖
        Object sharedInstance = getSingleton(beanName);
    // 缓存中有直接返回
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                } else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
      // 如果是FactoryBean需要获取其创建的对象
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        } else {
            // prototype类型如果产生循环依赖则无法解决
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // 如果当前工厂没有,就向上查找其父工厂
      BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                } else if (args != null) {
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                } else {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

      // 如果不仅仅做类型检查
      // 就标记一下是创建bean
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            try {
        // XML中定义的bean可能会有parent,如果有进行合并
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
                
        // 如果设置了前置依赖,先初始化依赖
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        try {
                            getBean(dep);
                        } catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

                // dependsOn处理完成以后,就可以初始化自身了
                if (mbd.isSingleton()) {
          // 通过lambda表达式生成的ObjectFactory来创建对象
          // 创建完成以后放入缓存
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }   catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
          // 同样得处理FactoryBean的情况
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                } else if (mbd.isPrototype()) { // prototype无关缓存,每次都重新创建就完事了
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    } finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                } else { // 既不是singleton也不是prototype,就只能通过指定的Scope去创建了
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }   finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }   catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }   catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // 检查一下类型是否匹配
    // 如果类型不匹配,尝试进行转换
    // 比如说容器中存放的是Number,requiredType是String
    if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            } catch (TypeMismatchException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }

其中最重要的就是重载的getSingleton(...)方法,它定义在AbstractBeanFactory的父类DefaultSingletonBeanRegistry中:

    @Override
    @Nullable
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 首先查看缓存中是否存在
        Object singletonObject = this.singletonObjects.get(beanName);
    // 缓存中没有,并且正处在创建过程中(比如正解析依赖)
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
        // 再看看有没有提前暴露出来
                singletonObject = this.earlySingletonObjects.get(beanName);
        // 如果没有提前暴露出来并且允许提前暴露的话
                if (singletonObject == null && allowEarlyReference) {
          // 那就通过ObjectFactory去创建了
                    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;
    }

    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,
                            "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正处在创建过程中
                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) {
                    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;
                    }
          // 标记bean创建完成
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
          // 添加到一级缓存
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }

  前文提到Spring是基于缓存来解决循环依赖的,这里的缓存指的就是getSingleton(String, boolean)方法中涉及的三级缓存:

    /** Cache of singleton objects: bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of singleton factories: bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** Cache of early singleton objects: bean name --> bean instance */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
  • singletonObjects:用于保存bean名称bean实例之间的映射关系
  • singletonFactories:用于保存bean名称创建bean的工厂之间的映射关系
  • earlySingletonObjects:也是用于保存bean名称bean实例之间的映射关系,与singletonObjects不同的是,存放在earlySingletonObjects中的bean实例,当它还处在创建过程中的时候就可以通过BeanFactory#getBean(...)获取到了,其目的是用来检测循环引用

一级缓存在bean完全初始化以后设置,二级缓存由三级缓存提升而来,三级缓存是在哪里设置的呢?getSingleton(String, ObjectFactory<?>)中使用到了ObjectFactory,而 ObjectFactory#getObject()又调用了createBean(...),继续往下追踪,最后来到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

    // 解析beanName对应的beanClass
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

    // 为lookup method服务
        try {
            mbdToUse.prepareMethodOverrides();
        } catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // 让InstantiationAwareBeanPostProcessor类型的处理器得到执行
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        } catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
      // 真正的创建逻辑代理给doCreateBean
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isDebugEnabled()) {
                logger.debug("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            throw ex;
        } catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }

发现创建bean的逻辑被代理给了doCreateBean(...),继续查看doCreateBean(...),刨去无关代码后终于找到了设置三级缓存的逻辑。

// 是singleton类型的bean,且正处在创建过程中
// allowCircularReferences默认是true
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");
  }
  // 此时就会将创建这个bean的ObjectFactory存入三级缓存
  addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

至此,Spring是如何解决循环依赖的就比较清晰了。

为什么是三级缓存

  之所以使用三级缓存,是为了可扩展性。仔细观察存入三级缓存的ObjectFactory,可以看到它调用了getEarlyBeanReference(...)

    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;
    }

这个方法主要是判断了一下是否存在SmartInstantiationAwareBeanPostProcessor类型的BeanPostProcessor,如果有的话就逐个执行。SmartInstantiationAwareBeanPostProcessor主要用在Spring框架内部,诸如AutowiredAop proxy均是在这一层实现的。如果只使用两级缓存,bean的创建就无法延迟执行,也就没有机会进行额外处理了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容