springソース解析のモデルモデルのサイクル依存性

4258 ワード

ご存知のように、Springは私達の対象の創建を管理して、廃棄して、全体のbeanのライフサイクルを管理しています.しかし、オブジェクトの作成過程においては、2つのbeanの間で相互に引用することができる特殊な状況があります.例えば、次のTestAでTestBを引用しました.TestAではTestAを引用しました.つまり、私がいて、あなたがいます.
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 prototypesCurrentlyInCreation = new NamedThreadLocal<>("Prototype beans currently in creation");
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注入のサイクル依存性を含めて、単一の例を紹介します.