Springがこれを解決する方法:Bean AはBean Bに依存し、Bean BはBean Aに依存しています。
Springがこれを解決する方法:Bean AはBean Bに依存し、Bean BはBean Aに依存しています。
回答:
他の答えが言ったように、Springはそれを処理し、Beanを作成し、必要に応じてそれらを注入します。
結果の1つは、Bean注入/プロパティ設定が、XMLワイヤリングファイルが示唆するように見える順序とは異なる順序で発生する可能性があることです。したがって、プロパティセッターは、既に呼び出されている他のセッターに依存する初期化を行わないように注意する必要があります。これに対処する方法は、InitializingBeanインターフェースを実装するものとしてBeanを宣言することです。これにはメソッドを実装する必要afterPropertiesSet()があり、ここで重要な初期化を行います。(重要なプロパティが実際に設定されていることを確認するためのコードも含めます。)
春のリファレンスマニュアルでは、円形の依存関係が解決される方法を説明します。豆は最初にインスタンス化され、次に相互に注入されます。
このクラスを考えてみましょう:
package mypackage;
public class A {
public A() {
System.out.println("Creating instance of A");
}
private B b;
public void setB(B b) {
System.out.println("Setting property b of A instance");
this.b = b;
}
}
そして同様のクラスB:
package mypackage;
public class B {
public B() {
System.out.println("Creating instance of B");
}
private A a;
public void setA(A a) {
System.out.println("Setting property a of B instance");
this.a = a;
}
}
この構成ファイルがある場合:
<bean id="a" class="mypackage.A">
<property name="b" ref="b" />
</bean>
<bean id="b" class="mypackage.B">
<property name="a" ref="a" />
</bean>
この構成を使用してコンテキストを作成すると、次の出力が表示されます。
Creating instance of A
Creating instance of B
Setting property a of B instance
Setting property b of A instance
aがに注入されたb場合、aまだ完全に初期化されていないことに注意してください。
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
私が使用しているコードベース(100万行以上のコード)では、起動時間が長く、約60秒で問題がありました。12000以上のFactoryBeanNotInitializedExceptionが発生していました。
私がしたことは、AbstractBeanFactory#doGetBeanに条件付きブレークポイントを設定することでした
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;
}
ここでdestroySingleton(beanName)、条件付きブレークポイントコードで例外を出力しました。
System.out.println(ex);
return false;
どうやらこれは、FactoryBeanが循環依存グラフに関与しているときに発生します。ApplicationContextAwareと InitializingBeanを実装し、手動でBeanを挿入することで解決しました。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class A implements ApplicationContextAware, InitializingBean{
private B cyclicDepenency;
private ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
ctx = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
cyclicDepenency = ctx.getBean(B.class);
}
public void useCyclicDependency()
{
cyclicDepenency.doSomething();
}
}
これにより、起動時間が約15秒に短縮されました。
したがって、春がこれらの参照を解決するのに適しているとは必ずしも想定しないでください。
このため、今後の多くの問題を防ぐために、AbstractRefreshableApplicationContext#setAllowCircularReferences(false)で循環依存関係の解決を無効にすることをお勧めします。
問題->
Class A {
private final B b; // must initialize in ctor/instance block
public A(B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
//原因:org.springframework.beans.factory.BeanCurrentlyInCreationException:「A」という名前のBeanの作成エラー:要求されたBeanは現在作成中です:解決できない循環参照はありますか?
ソリューション1->
Class A {
private B b;
public A( ) { };
//getter-setter for B b
}
Class B {
private A a;
public B( ) { };
//getter-setter for A a
}
ソリューション2->
Class A {
private final B b; // must initialize in ctor/instance block
public A(@Lazy B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
それだけです。aandをインスタンス化しb、それぞれを(setterメソッドを使用して)他のオブジェクトに注入します。
どうしたの?
春のリファレンスから:
通常、Springが正しいことを行うと信頼できます。コンテナーのロード時に、存在しないBeanへの参照や循環依存関係などの構成の問題を検出します。Springは、Beanが実際に作成されたときに、できるだけ遅くプロパティを設定し、依存関係を解決します。
Springコンテナは、セッターベースの循環依存関係を解決できますが、コンストラクタベースの循環依存関係の場合は、ランタイム例外BeanCurrentlyInCreationExceptionが発生します。Setterベースの循環依存関係の場合、IOCコンテナーは、協調型Beanを挿入する前にそれを完全に構成する通常のシナリオとは異なる方法で処理します。たとえば、Bean AがBean Bに依存し、Bean CのBean Bに依存している場合、コンテナはCを完全に初期化してからBに注入し、Bが完全に初期化されると、Aに注入されます。ただし、循環依存の場合は、1つ完全に初期化される前に、他のBeanに注入されます。
AがBに依存しているとすると、SpringはまずAをインスタンス化し、次にBをインスタンス化してから、Bのプロパティを設定し、次にBをAに設定します。
しかし、BもAに依存している場合はどうでしょうか。
私の理解は次のとおりです:SpringはAが構築された(コンストラクターが実行された)が、完全に初期化されていない(すべての注入が行われたわけではない)ことを発見しました。現時点では、完全に初期化されたAインスタンスをBに変換します。Bが完全に初期化された後、Aに設定され、最後にAが完全に開始されました。
つまり、事前にAをBに公開するだけです。
コンストラクターを介した依存関係の場合、SprintはBeanCurrentlyInCreationExceptionをスローするだけです。この例外を解決するには、コンストラクター引数を介して他に依存するBeanのlazy-initをtrueに設定します。
一般にコンストラクター注入を使用していて、プロパティ注入に切り替えたくない場合は、Springのlookup-method -injectionにより、一方のBeanが他方を遅延検索するため、循環依存関係を回避できます。こちらを参照してください:http : //docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
2つのBeanが相互に依存している場合、両方のBean定義でコンストラクター注入を使用しないでください。代わりに、いずれかのBeanでセッター注入を使用する必要があります。(もちろん、両方のBean定義でセッターインジェクションを使用できますが、両方のコンストラクターインジェクションは 'BeanCurrentlyInCreationException'をスローします
「https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resources-resource」にあるSpringドキュメントを参照してください