Spring はすべての循環依存関係を解決できるでしょうか?

厳密に言うと、解決できないわけではありません。すべての問題を解決する方法はありますが、追加の設定が必要です。これはこの記事の主題ではありません。ブラザー ソングは後で記事を作成し、友人と詳細に話し合う予定です。

1. コンストラクターベースのインジェクション

依存オブジェクトがコンストラクターに基づいて挿入される場合、実行中にエラーが報告されます。コードは次のとおりです。

 
 

ジャワ

コードをコピーする

@Service public class AService { BService bService; public AService(BService bService) { this.bService = bService; } } @Service public class BService { AService aService; public BService(AService aService) { this.aService = aService; } }

実行時エラーは次のとおりです。

原因分析:

前回の記事では、次の図に示すように、循環依存関係を解決するアイデアはキャッシュを追加することであると述べました。

最初に AService の元のオブジェクトが作成され、バッファ プールに格納され、その後 AService に注入する必要がある外部 Bean が処理される、などと言います。 ただし、AService が依存する BService がコンストラクタを介して注入される場合、 AService が元のオブジェクトの場合は BService が必要となり、BService が作成される場合は AService が必要となり、無限ループに陥り、このような循環依存関係を実行するとエラーが発生します。

さらに、AService の @Autowired を通じて BService を注入すると、実行できるはずです。コードは次のとおりです。

 
 

ジャワ

コードをコピーする

@Service public class AService { @Autowired BService bService; } @Service public class BService { AService aService; public BService(AService aService) { this.aService = aService; } }

上記のコードにより、AServiceの元のオブジェクトが無事作成されてキャッシュプールに配置され、BServiceの作成に必要なAServiceもキャッシュから取得できるので実行することができます。

2. プロトタイプオブジェクト

循環依存関係の両方のスコープがプロトタイプである場合、循環依存関係も失敗します。コードは次のとおりです。

 
 

ジャワ

コードをコピーする

@Service @Scope("prototype") public class AService { @Autowired BService bService; } @Service @Scope("prototype") public class BService { @Autowired AService aService; }

この種の循環依存関係も実行時にエラーを報告します。エラー メッセージは次のとおりです (前のエラー メッセージと同じです)。

原因分析:

スコープはプロトタイプです。つまり、Bean は必要になるたびにその場で作成され、キャッシュに保存する必要はありません。そして、AServiceにはBServiceが必要なので、現場でBServiceを作りに行き、その結果、BServiceにはAServiceが必要になり、現場で作り続け、AServiceにはBServiceが必要になり…という無限ループに陥ってしまいました。

3. @非同期

@Async アノテーションが付けられた Bean は循環依存関係を生成します。コードは次のとおりです。

 
 

ジャワ

コードをコピーする

@Service public class AService { @Autowired BService bService; @Async public void hello() { } } @Service public class BService { @Autowired AService aService; }

エラーメッセージは次のとおりです。

実際、このエラー メッセージからも、AService の元のオブジェクトが BService に挿入されていることがわかりますが、AService は後続の処理フローで AOP によってプロキシされ、新しいオブジェクトが生成され、BService が最終的なものではありません。 Aサービスだから、うまくいかない!

「前回の記事で、3 次キャッシュが AOP 問題を解決するものだと言いませんでしたか? なぜここでは AOP を解決できないのですか?」と質問する人もいます。

次の 2 つの前提条件を理解してください。

初め:

実際、ほとんどの AOP 循環依存関係には問題はありませんが、この @Async は単なる特殊なケースです。一般的な AOP は、プロキシ オブジェクトが生成されるポストプロセッサ AbstractAutoProxyCreator によって処理されます。AbstractAutoProxyCreator ポストプロセッサは SmartInstantiationAwareBeanPostProcessor インターフェイスのサブクラスであり、AbstractAutoProxyCreator ポストプロセッサは SmartInstantiationAwareBeanPostProcessor インターフェイスを書き換えます。getEarlyBeanReference メソッド; 一方、@Async は AsyncAnnotationBeanPostProcessor によってプロキシ オブジェクトを生成します, AsyncAnnotationBeanPostProcessor も SmartInstantiationAwareBeanPostProcessor のサブクラスですが、getEarlyBeanReference メソッドを書き換えません。デフォルトでは、getEarlyBeanReference メソッドは受信した Bean をそのままの状態で返します。

2番目:

Bean が初期化されると、Bean の作成後に 2 つのメソッドが実行されます。

  • PopulateBean: このメソッドはプロパティの入力に使用されます。
  • InitializeBean: このメソッドは、Bean インスタンスの初期化、ファクトリ コールバック、init メソッド、およびさまざまな BeanPostProcessor の実行に使用されます。

まずこれら 2 つの点を理解してから、上記のコードの実行プロセスについて説明します。

  1. まず、AService が初期化され、初期化が完了した後、3 次キャッシュに格納されます。
  2. PopulateBeanメソッドを実行してAServiceの属性を埋め込むと、BServiceが必要であることが判明したのでBServiceを初期化します。
  3. BServiceを初期化してAServiceが必要だったので、キャッシュプールに探しに行き、見つかったので使ってみたのですが、、、!ここで見つかった AService はプロキシ オブジェクトではなく、元のオブジェクトです。AService の ObjectFactory ファクトリは 3 次キャッシュに保存されているため、AService に対して事前に AOP を実行する場合、SmartInstantiationAwareBeanPostProcessor のポストプロセッサ型で getEarlyBeanReference メソッドが実行され、通常の AOP であれば getEarlyBeanReference メソッドを呼び出すことで最終的に AOP がトリガーされます。ただし、ここで実行されるのは AsyncAnnotationBeanPostProcessor の getEarlyBeanReference メソッドであり、追加の処理を行わずに元の Bean を返すだけです。
  4. BService が作成されると、AService は初期化を継続し、initializeBean メソッドを実行します。
  5. このinitializeBeanメソッドでは、AsyncAnnotationBeanPostProcessorをはじめとする様々なポストプロセッサが実行されますが、その際にAsyncAnnotationBeanPostProcessorのpostProcessAfterInitializationメソッドが呼び出され、このメソッド内でAServiceのプロキシオブジェクトが生成されます。
  6. initializeBean メソッドの実行後、AService は最終 Bean がまだ元の Bean であるかどうかを引き続きチェックします。そうでない場合は、現在の Bean が他の Bean によって参照されているかどうかをチェックします。参照されている場合は、例外がスローされます。 . それが上の写真にある異常情報です。

さて、これらは、Spring がデフォルトでは解決できない、Song Ge が共有した 3 つの循環依存関係です。実際、解決することが不可能ではなく、追加の設定で解決できます。もちろん、これらの追加の設定は、この記事の焦点. ソン・ゲは後で来ます. 紹介~

さらに、循環依存関係に関する最近の 2 つの記事にはまだソース コード分析が含まれていません。まず考えを明確にして、ブラザー ソングは後でソース コード分析に関する記事を公開します~

おすすめ

転載: blog.csdn.net/BASK2312/article/details/131811973