Spring之InitializeBean、earlySingletonExposure、getSingleton,两级缓存能解决循环依赖么?

InitializeBean

 总览如下图:

 此处忽略,后续会处理并设置对应的属性(判断bean的类型,是这些忽略的类型,将为其设置属性)。

三级缓存(保证对象的唯一)

boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
    // 从缓存中获取具体对象
    Object earlySingletonReference = this.getSingleton(beanName, false);
    // earlySingletonReference 只有在检测到有循环依赖时才有值
    if (earlySingletonReference != null) {
        // exposedObject 没有在初始化方法中被改变,也就是没有被增强
        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];
                    // 返回false,说明依赖还没有实例化好
                    if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
               }
               // 因为bean创建后所依赖的bean一定是已经创建的
               // actualDependentBeans不为空,表示当前bean创建后其依赖的bean没有创建完成,也就是说,循环依赖的bean没有创建(实例化)
               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.");
                    }
                }
            }
        }

getSingleton

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		// 因为创建过程中需要操作 singletonObjects。所以需要加锁
		synchronized (this.singletonObjects) {
			// 1. 再次尝试获取bean,判断bean是否已经加载。如果加载直接返回。
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				// 2. 判断,如果当前beanFactory正在被销毁则直接抛出异常,不允许创建单例bean
				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 + "'");
				}
				// 3. 做一些bean创建前的准备工作: 记录beanName 正在加载的状态(添加到 singletonsCurrentlyInCreation 缓存中),若bean已经正在加载,则抛出异常。为了解决循环引用的问题
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// 4. 通过回调方式获取bean实例。
					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;
					}
					// 5. 加载单例后的处理方法调用 : 删除bean正在创建的记录(从 singletonsCurrentlyInCreation  中移除 beanName)
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					// 6. 加入到缓存中,并删除加载bean过程中所记录的各种辅助状态
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

	...
	// 主要还是对几个缓存map的操作
	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);
		}
	}
	...
	// 不包含 && 添加失败 :则认为Bean正在创建中,抛出异常
	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}
	...
	// 不包含 && 移除失败 :认为Bean 已经创建结束,抛出异常。
	protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

Spring现有两级缓存能解决循环依赖么?

不能!

【保留一二级singletonObjectsearlySingletonObjects

流程:

实例化A ->将半成品的A放入earlySingletonObjects ->填充A的属性时发现取不到B->实例化B->将半成品的B放入earlySingletonObjects->earlySingletonObjects中取出A填充B的属性->将成品B放入singletonObjects,并从earlySingletonObjects中删除B->B填充到A的属性中->将成品A放入singletonObjects并删除earlySingletonObjects

这样的流程是线程安全的,不过如果A上加个切面(AOP),这种做法就没法满足需求了,因为earlySingletonObjects中存放的都是原始对象,而我们需要注入的其实是A的代理对象。

【保留一三级singletonObjectssingletonFactories

流程:

实例化A ->创建A的对象工厂并放入singletonFactories ->填充A的属性时发现取不到B->实例化B->创建B的对象工厂并放入singletonFactories->singletonFactories中获取A的对象工厂并获取A填充到B->将成品B放入singletonObjects,并从singletonFactories中删除B的对象工厂->B填充到A的属性中->将成品A放入singletonObjects并删除A的对象工厂。

同样,这样的流程也适用于普通的IOC已经有并发的场景,但如果A上加个切面(AOP)的话,这种情况也无法满足需求。

因为拿到ObjectFactory对象后,调用ObjectFactory.getObject()方法最终会调用getEarlyBeanReference()方法,getEarlyBeanReference这个方法每次从三级缓存中拿到singleFactory对象,执行getObject()方法又会产生新的代理对象

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值