今回は、循環依存の問題を完全に解決します!

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に配置されることです。

推奨閲覧:ポータル

この記事があなたに役立つと思うなら、あなたはそれを好きでそれをサポートするためにそれをフォローすることができます、またはあなたは私のパブリックアカウントをフォローすることができます。

 

おすすめ

転載: blog.csdn.net/weixin_50205273/article/details/108652806