Springで循環依存関係を解決する方法は、プロパティが単一のデフォルトシングルトンBeanで相互に参照するシナリオである必要があります。たとえば、いくつかのBean間の相互参照:
または
セッターモードプロトタイプ、プロトタイプ
「プロトタイプ」スコープBeanは各Beanリクエストのインスタンスを提供するため、プロトタイプシナリオは循環依存関係をサポートしていません。Springコンテナはキャッシュしないため、作成されたBeanを事前に公開できず、異常な。
コンストラクターパラメーターの循環依存関係
Springコンテナは、作成中の各Bean識別子を「現在作成されているBeanプール」に入れ、Bean識別子は作成プロセス中にこのプールに残ります。
したがって、Beanの作成プロセス中にすでに「現在作成されているBeanプール」にいることが判明した場合、循環依存関係を示すBeanCurrentlyInCreationExceptionがスローされ、作成されたBeanは「現在作成されているBeanプール」から削除されます。
Springコンテナは最初にシングルトンAを作成し、AはBに依存し、次にAを「現在作成されているBeanプール」に入れ、次にBを作成し、BはCに依存し、次にBを「現在作成されているBeanプール」に入れてから作成します。 CとCはAに依存しますが、現時点ではAはすでにプールにあるため、プール内のBeanは初期化されていないため、エラーが報告されます(初期化されたBeanはプールから移動されます)除く)。
セッターモードシングルトン、デフォルトモード
では、デフォルトのシングルトン属性注入シナリオでは、Springは循環依存関係をどのようにサポートしますか?
循環依存関係を解決する必要があるため、依存関係が存在する必要があります。
AとB、A-> B、B-> A、および2つは@Autowiredを介して相互に注入されます。
Aから開始することを前提としています。つまり、最初にAオブジェクトを作成し、次にBオブジェクトを作成し、次にリフレクション(fieldB.set(a、b))によってBオブジェクトをAオブジェクトの属性に設定し、Bの作成時にそれを見つけます。この場合も同様に、Bの属性に設定されたAオブジェクトを見つけたいのですが、システム内に存在できるAオブジェクト(シングルトン)は1つだけです。
この問題を解決するには、以前に作成されたAオブジェクトを保存する必要がありますか?キャッシュに格納されていると仮定しますが、後でBオブジェクトを使用する場合は、最初にキャッシュ内を検索してもよいでしょうか。!
したがって、循環依存関係を解決する方法は、作成されたすべてのオブジェクトを保存することです。後でオブジェクトを作成するときに依存関係がある場合は、キャッシュに移動して見つけます。見つかった場合は、作成中のオブジェクトの属性に直接設定し、見つからない場合は新しいオブジェクトを作成します。オブジェクトは、作成されてキャッシュに保存されるオブジェクトに与えられます。
実際、Springでも同じことが言えますが、キャッシュは1つだけでなく4つあります。
詳細については、この記事をご覧ください。
https://juejin.im/post/6844903715602694152
Springは循環依存関係を解決します
まず、Springは3つのマップを内部的に保持しています。これは、通常3レベルのキャッシュと呼ばれています。
SpringのDefaultSingletonBeanRegistryクラスには、クラスの上に3つのマップがぶら下がっています。
- singletonObjectsは、一般的に「シングルトンプール」および「コンテナ」として知られている、最も身近な友人であり、シングルトンBeanが作成された場所をキャッシュします。
- Beanのオリジナルファクトリを作成するためのsingletonFactoriesマッピング
- earlySingletonObjectsは、Beanの初期参照をマップします。つまり、このマップ内のBeanは完全ではなく、「Bean」ではなくインスタンスと呼ぶこともできません。
後者の2つのマップは、実際には「飛び石」レベルにあり、Beanを作成するときに役立つだけで、作成後にクリアされます。
なぜ後者の2つのマップが足がかりになるのでしょうか?最終的にsingletonObjectsに配置されるBeanが、必要な「クールでホワイト」のカップであると仮定します。
次に、Springは2つのカップ、つまりsingletonFactoriesとearlySingletonObjectsを準備し、数回前後に「注ぎ」、お湯を「涼しい白く開いた」状態に乾燥させ、singletonObjectsに入れます
循環依存の性質
2つのクラスAとBを定義します。
パブリッククラスA { プライベートB b; public B getB(){ return b; } public void setB(B b){ this.b = b; } }
public class B { public A getA(){ return a; } public void setA(A a){ this.a = a; } プライベートA a; }
パブリッククラスCircularDependency { private static Map <String、Object> cacheMap = new HashMap <>(2); public static void main(String [] args)throws Exception { //仮定装扫描出来的対象 Class [] classes = {A.class、B.class}; // (クラスaClass:classes){ getBean(aClass);の仮装项目初始化実例化所有bean } // System.out.println(getBean(B.class).getA()== getBean(A.class));を確認します System.out.println(getBean(A.class).getB()== getBean(B.class)); } private static <T> T getBean(Class <T> beanClass)throws Exception { //この記事では、単純な小文字のクラス名を使用してBeanの命名規則を置き換えます String beanName = beanClass.getSimpleName()。toLowerCase(); //すでにBeanである場合は、直接返す if(cacheMap.containsKey(beanName)){ return(T)cacheMap.get(beanName); } //オブジェクトを変更する Objectオブジェクト自体をインスタンス化する= beanClass.getDeclaredConstructor()。newInstance(); //キャッシュに 入れるcacheMap.put(beanName、object); //すべてのフィールドをインジェクトする必要のあるBeanとして扱い、現在のBeanに作成してインジェクトする Field [ ] fields = object.getClass()。getDeclaredFields(); for(Field field:fields){ field.setAccessible(true); //注入 するフィールドのクラスクラスを取得<?> fieldClass = field.getType(); String fieldBeanName = fieldClass.getSimpleName()。toLowerCase(); //注入されるBeanがすでにキャッシュMapにある場合、次に、キャッシュマップの値をフィールドに挿入します //キャッシュが作成を続行しない場合 field.set(object、cacheMap.containsKey(fieldBeanName)?CacheMap.get(fieldBeanName):getBean(fieldClass)); } //プロパティ充填が完了し、 (T)オブジェクトを返す; } }
このコードの効果は、循環依存関係が実際に処理され、処理が完了すると、完全な「Bean」がcacheMapに配置されることです。
推奨閲覧:ポータル
この記事があなたに役立つと思うなら、あなたはそれを好きでそれをサポートするためにそれをフォローすることができます、またはあなたは私のパブリックアカウントをフォローすることができます。