spring 循环依赖

单例bean循环依赖:

先创建ABean

1.0. 记录正在创建ABean singletonCurrentlyInCreation<ABean>
1.1.实例化ABean–>得到一个对象–>存入singletonFactories
1.2. 填充BBean属性–>去单例池找BBean–>没有就创建
1.3. 进行其他依赖注入
1.4. 初始化前,初始化
1.5. 初始化后
1.6. 放入单例池

创建BBean
2.1. 实例化BBean–>得到一个对象
2.2. 填充ABean属性–>去单例池找ABean–>没有就判断creatingSet–>出现循环依赖–>earlySingletonObjects–>singletonFactories–>Lambda表达式–>执行–> 执行结果创建ABean代理对象或者ABean原始对象,存入earlySingletonObject
2.3. 进行其他依赖注入
2.4. 初始化前,初始化
2.5. 初始化后
2.6. 放入单例池

创建CBean
3.1. 实例化BBean–>得到一个对象
3.2. 填充ABean属性–>去单例池找ABean–>没有就判断creatingSet–>出现循环依赖–>从earlySingletonObjec获取ABean
3.3. 进行其他依赖注入
3.4. 初始化前,初始化
3.5. 初始化后
3.6. 放入单例池

在ABean执行到1.2时会去创建BBean,进入到BBean的生命周期,造成循环依赖

spring为了解决循环依赖进行了三级缓存

1.singletonObjects 单例池
2.earlySingletonObjects 没有经过完整生命周期的单例对象,主要作用时保存单例bean对象,而跳出循环依赖
3.singletonFactories 实例化后没有经过依赖注入的对象,主要作用时生成单例bena对象,并将其存入earlySingletonObjects

//this.getEarlyBeanReference(beanName, mbd, bean)判断是否需要AOP,需要返回AOP代理对象,否则返回原始对象
//该逻辑在bean对象实例化后,依赖注入前
this.addSingletonFactory(beanName, () -> {return this.getEarlyBeanReference(beanName, mbd, bean);});

辅助

  1. singletonCurrentlyInCreation
  2. earlyProxyReferences
@Nullable
//从单例池获取bean
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    //判断bean是否在创建中
    if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
    	//从二级缓存earlySingletonObjects中获取bean对象
        singletonObject = this.earlySingletonObjects.get(beanName);
        //没有获取到bean对象并且允许循环依赖
        if (singletonObject == null && allowEarlyReference) {
            synchronized(this.singletonObjects) {
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                	//从二级缓存earlySingletonObjects中获取bean对象
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                    	//从三级缓存singletonFactories中获取singletonFactory对象
                        ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                        	//执行获取bean对象的逻辑
                            singletonObject = singletonFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }

    return singletonObject;
}

初始化后生成的代理对象和循环依赖生成的AOP代理对象不同导致的问题:

//以下逻辑在bean实例化之后
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);
            //bean初始化,返回bean对象,如果bean因为AOP以外的代理对象生成,且返回的是该对象
            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) {
        	//从单例池拿bean对象,如果因为循环依赖则会从二级缓存中拿到AOP生成的代理对象
            Object earlySingletonReference = this.getSingleton(beanName, false);
            if (earlySingletonReference != null) {
            	//如果是循环依赖生成的earlySingletonReference,判断exposedObject是否非AOP代理对象
                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);
                        }
                    }
					//如果是不同的代理对象,则提示ERROR(避免最后生成的对象不是AOP代理对象,但是循环依赖的BBean依赖注入的是ABean因为AOP生成的代理对象,可以通过在ABean的BBean属性上添加@Laze,则ABean中添加@Async(某些PostProcessor会新生成代理对象,@Transactional不是实现PostProcessor生成代理对象,则不会出现问题)的方法也不会抛出ERROR)
                    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.");
                    }
                }
            }
        }

@Lazy解决循环依赖

@Lazy注解会在bean进行依赖注入(以上步骤的第二步)时生成一个代理对象,不会影响bean之后的流程,则不会出现循环依赖。

原型bean循环依赖

原型bean无法解决循环依赖问题。

构造器的循环依赖

无法实例化对应bean则直接提示ERROR,可在构造器加@Lazy解决。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值