美文网首页
Spring中的循环依赖

Spring中的循环依赖

作者: anyoptional | 来源:发表于2021-04-20 09:28 被阅读0次

    循环依赖

      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的创建就无法延迟执行,也就没有机会进行额外处理了。

    相关文章

      网友评论

          本文标题:Spring中的循环依赖

          本文链接:https://www.haomeiwen.com/subject/hrrmlltx.html