美文网首页
Spring循环依赖

Spring循环依赖

作者: 追风还是少年 | 来源:发表于2023-09-04 14:11 被阅读0次

    什么是循环依赖?

    循环依赖在spring中指多个bean之间相互依赖,构成有向环,最简单的循环依赖是两个bean之间的循环依赖,如:bean A依赖bean B,bean B也依赖bean A;多个bean之间的循环依赖,如:A->B->C->A
    为了简单,后续都是以两个bean的循环依赖解释说明的。


    image.png

    在Java中依赖关系是通过把被依赖类定义为依赖类的属性,如:

    public class A {
        private B b;
    }
    
    public class B {
        private A a;
    }
    

    Spring中的bean的创建过程主要有实例化、属性填充、初始化。

    Spring 中bean依赖一般是通过@Autowire或@Resource注解来注入依赖的,在Spring中有主要有两种注入方式:

    • 构造函数注入
    @Component
    public class A {
       // A中注入了B
      @Autowired
      public A(B b){
        this.b = b
      }
      private B b;
    }
    
    @Component
    public class B {
        // B中也注入了A
        @Autowired
        public B(A a){
          this.a = a
        }
        
        private A a;
    }
    
    • 属性注入
    @Component
    public class A {
        // A中注入了B
        @Autowired
        private B b;
    }
    
    @Component
    public class B {
        // B中也注入了A
        @Autowired
        private A a;
    }
    

    我相信大家在使用Spring开发中或多或少应该遇到过因为Spring bean之间的循环依赖导致应用启动失败的情况。基于Spring的两种注入方式排列组合,bean之间的循环依赖以下四种情况:

    • A、B之间的循环依赖通过构造函数注入
    • A、B之间的循环依赖通过属性注入
    • A依赖B是通过属性注入,B依赖A是通过构造器注入
    • B依赖注入A是通过属性注入,A依赖B是通过构造函数注入

    这四种情况的循环依赖在Spring哪几种能解决,在几种不能解决呢?要解答这个问题需要了解在Spring中式怎么解决循环依赖的
    在Spring中是通过三级缓存来解决循环依赖的,分别是下面三级缓存:

    • 一级缓存(singletonObjects)
      存放最终形态的bean(如果存在代理,存放的代理后的bean)
      一般情况我们获取bean都是从这里获取的,但是并不是所有的bean都存放在这里,一些特殊的,比如原型的bean就不在里面。
    • 二级缓存(earlySingletonObjects)
      存放的是半成品的bean(属性未填充),即三级缓存中的ObjectFactory产生的对象
      主要作用是bean被AOP切面代理后,出现重复通过三级缓存中的ObjectFactory产生的新的对象,导致bean不是单例的了
    • 三级缓存(singletonFactories)
      存放的是ObjectFactory类型,用于产生bean对象
      ObjectFactory类的getObject方法最终调用的是getEarlyBeanReference()方法,该方法作用是产生原始对应或代理bean对象
    image.png

    判断bean是否需要提前暴露bean(生成ObjectFactory对象)及放入第三级缓存的条件:bean是单例且允许循环依赖且bean在创建中

            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));
            }
    
    public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
      protected <T> T doGetBean(
                String name, @Nullable Class<T> requiredType, @Nullable       
                Object[] args, boolean typeCheckOnly)
                throws BeansException {
            Object sharedInstance = getSingleton(beanName);
            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);
            }else{
                    if (mbd.isSingleton()) {
                        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);
                    }
        }
      }
    }
    
    public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
            implements AutowireCapableBeanFactory {
        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) {
                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 {
                        applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                    }
                    catch (Throwable ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Post-processing of merged bean definition failed", ex);
                    }
                    mbd.postProcessed = true;
                }
            }
    
            // Eagerly cache singletons to be able to resolve circular references
            // even when triggered by lifecycle interfaces like BeanFactoryAware.
            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));
            }
    
            // Initialize the bean instance.
            Object exposedObject = bean;
            try {
                populateBean(beanName, mbd, instanceWrapper);
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
            catch (Throwable ex) {
                if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                    throw (BeanCreationException) ex;
                }
                else {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
                }
            }
    
            if (earlySingletonExposure) {
                Object earlySingletonReference = getSingleton(beanName, false);
                if (earlySingletonReference != null) {
                    if (exposedObject == bean) {
                        exposedObject = earlySingletonReference;
                    }
                    else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                        String[] dependentBeans = getDependentBeans(beanName);
                        Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                        for (String dependentBean : dependentBeans) {
                            if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                                actualDependentBeans.add(dependentBean);
                            }
                        }
                        if (!actualDependentBeans.isEmpty()) {
                            throw new BeanCurrentlyInCreationException(beanName,
                                    "Bean with name '" + beanName + "' has been injected into other beans [" +
                                    StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                    "] in its raw version as part of a circular reference, but has eventually been " +
                                    "wrapped. This means that said other beans do not use the final version of the " +
                                    "bean. This is often the result of over-eager type matching - consider using " +
                                    "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                        }
                    }
                }
            }
    
            // Register bean as disposable.
            try {
                registerDisposableBeanIfNecessary(beanName, bean, mbd);
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
            }
    
            return exposedObject;
        }
    }
    
    public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
        /** Cache of singleton objects: bean name to bean instance. */
        // 一级缓存
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
        /** Cache of singleton factories: bean name to ObjectFactory. */
        // 三级缓存
        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
        /** Cache of early singleton objects: bean name to bean instance. */
        // 二级缓存
        private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
    
        private final Set<String> singletonsCurrentlyInCreation =
                Collections.newSetFromMap(new ConcurrentHashMap<>(16));
    
        public Object getSingleton(String beanName) {
            return getSingleton(beanName, true);
        }
    
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            // Quick check for existing instance without full singleton lock
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    synchronized (this.singletonObjects) {
                        // Consistent creation of early reference within full singleton lock
                        singletonObject = this.singletonObjects.get(beanName);
                        if (singletonObject == null) {
                            singletonObject = this.earlySingletonObjects.get(beanName);
                            if (singletonObject == null) {
                                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                                if (singletonFactory != null) {
                                    singletonObject = singletonFactory.getObject();
                                    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 + "'");
                    }
                    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;
            }
        }
    
        protected void addSingleton(String beanName, Object singletonObject) {
            synchronized (this.singletonObjects) {
                this.singletonObjects.put(beanName, singletonObject);
                this.singletonFactories.remove(beanName);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    
        protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
            Assert.notNull(singletonFactory, "Singleton factory must not be null");
            synchronized (this.singletonObjects) {
                if (!this.singletonObjects.containsKey(beanName)) {
                    this.singletonFactories.put(beanName, singletonFactory);
                    this.earlySingletonObjects.remove(beanName);
                    this.registeredSingletons.add(beanName);
                }
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Spring循环依赖

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