Spring DI过程以及如何解决循环依赖

    在spring创建bean的过程,如果出现了A依赖B,并且B依赖A的情况,那么这种情况称之为循环依赖。spring并不能够解决构造器注入的循环依赖,只能解决属性的循环依赖。
    spring创建bean,首先会调用doGetBean方法
     1.从容器中获取单例的bean
     2.如果不存在单例的bean,那么进行bean的实例化
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        String beanName = this.transformedBeanName(name);
          //从容器中获取单列bean
        Object sharedInstance = this.getSingleton(beanName);
        Object bean;
        if (sharedInstance != null && args == null) {
            bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
        } else {
                 //没有获取到,则进行bean的的初始化
                if (mbd.isSingleton()) {
                    sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });
                    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }   
        }
          return bean;
    }
   getSingleton方法获取bean的过程,采取了三级缓存的方式
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
        private final Map<String, Object> earlySingletonObjects = new HashMap(16);
  首先从singletonObjects 中获取,如果不存在再去earlySingletonObjects 中获取,再没有才去singletonFactories 获取。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
         // 从singletonObjects容器中获取bean
        Object singletonObject = this.singletonObjects.get(beanName);
          // singletonObjects容器没有bean,并且当前bean在创建过程中
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            synchronized(this.singletonObjects) {
                //从earlySingletonObjects容器获取bean
                singletonObject = this.earlySingletonObjects.get(beanName);
                //如果earlySingletonObjects没有并且allowEarlyReference为true
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }

        return singletonObject;
    }
单例bean初次创建时,会进入到下述方法,这个方法才去了匿名内部类的方式作为singletonFactory的形参,这样的话会首先执行getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法,再去执行匿名内部类里面的this.createBean(beanName, mbd, args)方法
getSingleton方法的主要内容在于beforeSingletonCreation,该方法会在容器中插入当前需要创建bean的beanName,标识当前bean已经在创建

Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16))

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized(this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                 this.beforeSingletonCreation(beanName);
                 singletonObject = singletonFactory.getObject();
                 return singletonObject;
        }
    }

然后使用到singletonFactory,所以需要执行匿名内部类中的createBean方法,可以看到createBean依次做了如下事情:

  • 创建bean的实例
  • 将创建好的bean放入singletonFactories 中,供其他bean引用
  • 依赖注入
  • 完成初始化并返回
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
            //创建bean实例
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }

                mbd.postProcessed = true;
            }
        }
        // 当前bean为单例,允许早起引用并且isSingletonCurrentlyInCreation为true的情况,addSingletonFactory将bean放入singletonFactories ,以便接下来依赖注入的时候可以获取到bean。其中isSingletonCurrentlyInCreation在getSingleton(String beanName, ObjectFactory<?> singletonFactory)的时候已经设置过。
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }

            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

        Object exposedObject = bean;

        try {
            this.populateBean(beanName, mbd, instanceWrapper);
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = this.getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        if (!this.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 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        try {
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }

总结

再以A和B的例子,在A创建时,一开始肯定是没有bean,那么必然会调用getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法,这是标记A为正在创建中。
接下来创建A的实例(没有任何属性的注入),创建完成即将当前bean放入singletonFactories,然后接下来进行依赖注入B,也就是populateBean方法,执行B的过程发现需要A,此时getSingleton(String beanName, boolean allowEarlyReference)发现已经存在当前bean了,所以顺利完成B的创建,自然而然A的注入也顺利完成
最后完成全过程的初始化
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容