春に@Asyncをする方法

Springで@Asyncを実行する方法

1. 概要

この記事では、asynchronous execution support in Spring@Asyncアノテーションについて説明します。

簡単に言えば、Beanのメソッドに@Asyncアノテーションを付けると、execute in a separate threadになります。 呼び出し元は、呼び出されたメソッドの完了を待ちません。

Springの興味深い側面の1つは、そのルートに移動する場合、フレームワークalso has support for async processingでのイベントサポートです。

参考文献:

春のイベント

Springのイベントの基本-シンプルなカスタムイベントを作成し、それを公開して、リスナーで処理します。

@Asyncを使用したSpring Securityコンテキストの伝播

@Asyncアノテーションを使用するときにSpring Securityコンテキストを伝播する短い例

Spring MVCおよびSpring Securityによるサーブレット3非同期サポート

Spring MVCでの非同期リクエストに対するSpring Securityサポートの簡単な紹介。

2. 非同期サポートを有効にする__

enabling asynchronous processingJava configurationから始めましょう–単に@EnableAsyncを構成クラスに追加することによって:

@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }

enableアノテーションで十分ですが、ご想像のとおり、構成にはいくつかの簡単なオプションもあります。

  • *annotation* – byのデフォルト、@EnableAsyncはSpringの@Async注釈とEJB 3.1javax.ejb.Asynchronousを検出します。このオプションは、他のユーザー定義の注釈タイプを検出するためにも使用できます

  • mode –使用する必要のあるadviceのタイプを示します–JDKプロキシベースまたはAspectJウィービング

  • proxyTargetClass –使用する必要のあるproxyのタイプを示します–CGLIBまたはJDK。この属性は、modeAdviceMode.PROXYに設定されている場合にのみ有効です。

  • orderAsyncAnnotationBeanPostProcessorを適用する順序を設定します。デフォルトでは、既存のすべてのプロキシを考慮に入れるために、最後に実行されます

非同期処理は、XML configurationを使用して有効にすることもできます–task名前空間を使用します。


3. @Async注釈

まず、ルールを確認しましょう–@Asyncには2つの制限があります。

  • publicメソッドにのみ適用する必要があります

  • 自己呼び出し-同じクラス内から非同期メソッドを呼び出します-動作しません

理由は単純です–プロキシできるようにthe method needs to be public。 また、self-invocation doesn’t workはプロキシを迂回して直接に元のメソッドを呼び出すからである。

3.1. ボイドリターンタイプのメソッド

以下は、戻り値の型がvoidのメソッドを非同期に実行するように構成する簡単な方法です。

@Async
public void asyncMethodWithVoidReturnType() {
    System.out.println("Execute method asynchronously. "
      + Thread.currentThread().getName());
}

3.2. 戻り値の型を持つメソッド

@Asyncは、戻り値の型を持つメソッドにも適用できます–将来の実際の戻り値をラップすることによって:

@Async
public Future asyncMethodWithReturnType() {
    System.out.println("Execute method asynchronously - "
      + Thread.currentThread().getName());
    try {
        Thread.sleep(5000);
        return new AsyncResult("hello world !!!!");
    } catch (InterruptedException e) {
        //
    }

    return null;
}

Springは、Futureを実装するAsyncResultクラスも提供します。 これは、非同期メソッド実行の結果を追跡するために使用できます。

次に、上記のメソッドを呼び出し、Futureオブジェクトを使用して非同期プロセスの結果を取得しましょう。

public void testAsyncAnnotationForMethodsWithReturnType()
  throws InterruptedException, ExecutionException {
    System.out.println("Invoking an asynchronous method. "
      + Thread.currentThread().getName());
    Future future = asyncAnnotationExample.asyncMethodWithReturnType();

    while (true) {
        if (future.isDone()) {
            System.out.println("Result from asynchronous process - " + future.get());
            break;
        }
        System.out.println("Continue doing something else. ");
        Thread.sleep(1000);
    }
}

4. エグゼキュータ

デフォルトでは、SpringはSimpleAsyncTaskExecutorを使用して、これらのメソッドを実際に非同期で実行します。 デフォルトは、アプリケーションレベルまたは個々のメソッドレベルの2つのレベルでオーバーライドできます。

4.1. メソッドレベルでエグゼキュータをオーバーライドする

必要なエグゼキューターは、構成クラスで宣言する必要があります。

@Configuration
@EnableAsync
public class SpringAsyncConfig {

    @Bean(name = "threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        return new ThreadPoolTaskExecutor();
    }
}

次に、エグゼキュータ名を@Asyncの属性として指定する必要があります。

@Async("threadPoolTaskExecutor")
public void asyncMethodWithConfiguredExecutor() {
    System.out.println("Execute method with configured executor - "
      + Thread.currentThread().getName());
}

4.2. アプリケーションレベルでのエグゼキュータのオーバーライド

構成クラスはAsyncConfigurerインターフェースを実装する必要があります。これは、getAsyncExecutor()メソッドを実装することを意味します。 ここで、アプリケーション全体のエグゼキュータを返します。これが、@Asyncアノテーションが付けられたメソッドを実行するためのデフォルトのエグゼキュータになります。

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        return new ThreadPoolTaskExecutor();
    }

}

5. 例外処理

メソッドの戻り値の型がFutureの場合、例外処理は簡単です–Future.get()メソッドは例外をスローします。

ただし、戻り値の型がvoidの場合、exceptions will not be propagated to the calling threadです。 したがって、例外を処理するために追加の構成を追加する必要があります。

AsyncUncaughtExceptionHandlerインターフェースを実装して、カスタム非同期例外ハンドラーを作成します。 キャッチされない非同期例外がある場合、handleUncaughtException()メソッドが呼び出されます。

public class CustomAsyncExceptionHandler
  implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(
      Throwable throwable, Method method, Object... obj) {

        System.out.println("Exception message - " + throwable.getMessage());
        System.out.println("Method name - " + method.getName());
        for (Object param : obj) {
            System.out.println("Parameter value - " + param);
        }
    }

}

前のセクションでは、構成クラスによって実装されたAsyncConfigurerインターフェースについて説明しました。 その一環として、getAsyncUncaughtExceptionHandler()メソッドをオーバーライドして、カスタム非同期例外ハンドラーを返す必要もあります。

@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    return new CustomAsyncExceptionHandler();
}

6. 結論

このチュートリアルでは、running asynchronous code with Springについて説明しました。 動作させるための非常に基本的な構成と注釈から始めましたが、独自のエグゼキューターや例外処理戦略の提供など、より高度な構成も検討しました。

そして、いつものように、この記事で紹介されている完全なコードはover on Githubで利用できます。