doCreateBeanメソッドでのBeanCurrentlyInCreationExceptionの分析

	   populateBean(beanName, mbd, instanceWrapper);
	   exposedObject = initializeBean(beanName, exposedObject, mbd);	
        。。。。	
       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 " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

Bean:元のオブジェクト

ExposureObject:初期化されたオブジェクト。プロキシオブジェクトの場合があります。

EarlySingletonReference:インスタンス化されているが初期化されていないオブジェクト。プロキシオブジェクトである可能性があります。オブジェクトearlySingletonReference = getSingleton(beanName、false)、getSingletonソースコードからわかるように、allowEarlyReferenceがfalseの場合、値は第1レベルと第2レベルのキャッシュでのみ取得され、第2レベルのキャッシュの値はによって割り当てられます。第3レベルのキャッシュ。オブジェクトがない場合循環参照がある場合、第3レベルのキャッシュの値が第2レベルのキャッシュに割り当てられることはなく、earlySingletonReferenceはnullになります。

        BeanCurrentlyInCreationExceptionをトリガーするには、exposedObjectをプロキシオブジェクトとして説明します。つまり、BeanはinitializeBeanメソッドでプロキシされます。また、BeanがAオブジェクト(A-> B-> A)などの循環参照オブジェクトである場合、ここでコードを実行すると、Bオブジェクトは完全に初期化され、Bで参照されるAは3番目からのものであるためです。 -レベルキャッシュで取得されたAオブジェクトですが、AオブジェクトはBが初期化された後にプロキシを実行するため、BのAはAが初期化された後のAとは異なり、例外がトリガーされます。スプリングは以下のif判定でチェックします

                if(!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)){                             actualDependentBeans.add(dependentBean);                         }

ifチェックは、次のように要約できます。オブジェクトが初期化された後にプロキシが実行され、オブジェクトが初期化前に他の初期化されたオブジェクトによって参照される場合、例外がトリガーされます。

@Asyncの処理は、初期化後にプロキシを実行することです。対応するBeanが周期的に依存している場合、例外がトリガーされます。

@Transactionalに対応するBeanが循環的に依存している場合、Beanに対応するプロキシは第3レベルのキャッシュから取得されたときに処理され、exposedObjectは初期化後も元のBeanオブジェクトであるため、exposedObjectとBeanは次のようになります。等しい。プロキシオブジェクトはレベルキャッシュから取得され、exposedObjectに割り当てられるため、最終的に返されるexposedObjectはプロキシオブジェクトであり、例外は発生しません。

 

おすすめ

転載: blog.csdn.net/sinat_33472737/article/details/109775826