web-dev-qa-db-ja.com

別の非同期メソッドから呼び出されたSpring非同期メソッド

私はSpring 4を使用していますが、奇妙な動作に気づきました...通常のインスタンスメソッドから非同期メソッドを複数回呼び出している場合、それらはすべて異なるスレッドで呼び出され、ランダムに終了します。しかし、別の非同期メソッドから非同期メソッドを複数回呼び出すと、それらは順番に終了します。私はこのようなものを持っています:

@Async
public void nonAsyncMethod() {
  for (int i = 0; i < 30; i++) {
     asyncMethod();
  }
}

@Async
public void asyncMethod() {
   ... something here
}

デフォルトの非同期エグゼキューターを使用しています。別のものを使用する必要がありますか?ただし、このエグゼキューターはスレッドを再利用せず、毎回別のスレッドを開始するため、問題ありません...単なる偶然でしょうか?しかし、私は10回以上試しました、そして私が最初の方法で非同期に戻らない場合、それらはランダムに終了します

22
spauny

あなたが説明しているのは、Spring AOPの古典的な落とし穴です。

つまり、Springが非同期動作を提供できるようにするには、実行時にクラスのプロキシを作成する必要があります。その後、プロキシは、コードを呼び出す前または後に、必要なことを何でも行います。しかし、あなたの場合、プロキシメカニズムは2番目の方法に適用されていません。

クラスのBeanがSpringを介して他のコンポーネントに注入されると、Springは実際には代わりにプロキシを注入します。そのため、プロキシの関連メソッドが呼び出されます。ただし、クラス内からメソッドを呼び出す場合、Spring AOPの制限により、プロキシは機能しませんが、代わりに通常のメソッドが呼び出されます-追加機能はありません。

そのため、asyncMethodは常に、それを呼び出した同じクラスの他のメソッドと同じスレッドで実行されます。

this 優れたブログ投稿、およびSpringドキュメントの this の一部を確認してください。

問題を回避するにはいくつかの方法があります(チェックアウト this )。コードをリファクタリングする必要はありませんが、非同期で両方のメソッドを機能させたい場合は、最も簡単な方法は次のとおりです。 2番目のメソッドを別のクラスにリファクタリングします。

54
geoand