springソース解析のモデルモデルのサイクル依存性
4258 ワード
ご存知のように、Springは私達の対象の創建を管理して、廃棄して、全体のbeanのライフサイクルを管理しています.しかし、オブジェクトの作成過程においては、2つのbeanの間で相互に引用することができる特殊な状況があります.例えば、次のTestAでTestBを引用しました.TestAではTestAを引用しました.つまり、私がいて、あなたがいます.
多例モードでのサイクル依存
Springでは、すべてのbeanがデフォルトで単一の例であるsingletonである.複数例のモードでのサイクル依存性は、Springでは解決できない.まずソースコードを見てください.ここにはプロトタイプのCurrenntlyInCreation変数があります.とても重要です.Springも説明しています.この変数は現在作成されているbeanNameを記録します.最後に、なぜこのようなマークが必要なのかを重点的に紹介します.
問題が来ました.もし異常を捨てないなら、どうなりますか?このようなセットがないとどうなりますか?みんなで考えてみてもいいです.このようなマークがない場合、testAは属性の割り当てを行う時、testBに依存していることを発見し、すぐにtestBを作成し、testBに属性の割り当てを行った時、またtestAに依存していることを発見しました.また、testAはtestBに依存して、testBを作成します.往復して死のサイクルを作って、永遠に出られなくなりました.だからSpringはこのような現象を避けるために、むしろ直接に異常を投げます.Springから見ても、どうやって解決するか分かりません.
次の記事では、単一の例でのコンストラクタの循環依存性、set注入のサイクル依存性を含めて、単一の例を紹介します.
public class TestA {
// TestB
private TestB testB;
// get,set
}
================================
public class TestB {
// TestA
private TestA testA;
// get,set
}
このような場合、なぜ循環依存が生じるのでしょうか?Springはどのようにしてこのような問題をうまく解決しましたか?私たちは問題を抱えて見続けます.多例モードでのサイクル依存
Springでは、すべてのbeanがデフォルトで単一の例であるsingletonである.複数例のモードでのサイクル依存性は、Springでは解決できない.まずソースコードを見てください.ここにはプロトタイプのCurrenntlyInCreation変数があります.とても重要です.Springも説明しています.この変数は現在作成されているbeanNameを記録します.最後に、なぜこのようなマークが必要なのかを重点的に紹介します.
/** Names of beans that are currently in creation */
private final ThreadLocal
doGetBeanを呼び出してbeanを作成すると、isProttypeCurrenntlyInCreation方法を呼び出して判断し、現在のbeanNameが現在のスレッド変数にあるかどうかを判断します.もし、BenCurentlyInCreation Exception異常を直接抛り出します./* , bean */
if (isPrototypeCurrentlyInCreation(beanName)) {
// ,
throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null && (curVal.equals(beanName) ||
(curVal instanceof Set && ((Set>) curVal).contains(beanName))));
}
初めて入力して作成した場合、変数には必ず格納されていません.falseに戻ります.続いて、ベフォートProttypeCreation方法を呼び出して、現在のベナンNameを現在のスレッドの変数に入れて保存して、前のマークを付けて、現在のbeanはすでに作成し始めました.これからの循環依存に備えて準備します.//IOC Bean
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
// (Prototype)
Object prototypeInstance = null;
try {
// : beforePrototypeCreation ,
beforePrototypeCreation(beanName);
// : Bean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// afterPrototypeCreation , IOC Bean
afterPrototypeCreation(beanName);
}
// Bean
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
//...
}
第二のステップはクリアービーンのメソッドを呼び出しますが、クリアービーンの実装は本当にdoCreateBeanです.ここでビーンの作成、属性依存注入、初期化など一連の操作を完了します.// Bean
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//...
try {
// : Bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
catch (BeanCreationException ex) {
// A previously detected exception with proper bean creation context already...
throw ex;
}
//...
}
// Bean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
//...
//
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//Bean ,
populateBean(beanName, mbd, instanceWrapper);
// Bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
//...
return exposedObject;
}
popullateBeanメソッドを呼び出すと、各属性のために値を割り当てます.上のTestA、TestBを例にとって、testAがtestBに依存していることを発見したら、次にgetBen(testB)に行きます.testBの作成プロセスはtestAと同じです.まずsetセットに行って、現在のbeanNameが作成中かどうかを取得します.ない場合はset操作を行い、現在のスレッド変数に保存します.続いてbeanの作成を行います.poputlateBeanメソッドを呼び出した時、testBはtestAに依存していることを発見します.その後、testAを作成します.isProttypeCurentlyInCreation方法を呼び出した時、この時のtestAはまだ属性の割り当てを行っていますので、完全な作成に成功していません.現在のbeanが作成中であることをお知らせします.問題が来ました.もし異常を捨てないなら、どうなりますか?このようなセットがないとどうなりますか?みんなで考えてみてもいいです.このようなマークがない場合、testAは属性の割り当てを行う時、testBに依存していることを発見し、すぐにtestBを作成し、testBに属性の割り当てを行った時、またtestAに依存していることを発見しました.また、testAはtestBに依存して、testBを作成します.往復して死のサイクルを作って、永遠に出られなくなりました.だからSpringはこのような現象を避けるために、むしろ直接に異常を投げます.Springから見ても、どうやって解決するか分かりません.
次の記事では、単一の例でのコンストラクタの循環依存性、set注入のサイクル依存性を含めて、単一の例を紹介します.