ホームページ  >  記事  >  Java  >  SpringBoot が非同期呼び出しをエレガントに実装する方法

SpringBoot が非同期呼び出しをエレガントに実装する方法

WBOY
WBOY転載
2023-05-12 22:04:041644ブラウズ

はじめに

  • 同期プログラミング: 同期プログラミングでは、タスクは一度に 1 つずつ実行され、1 つのタスクが完了した場合にのみ、次のタスクのブロックが解除されます。 。

  • 非同期プログラミング: 非同期プログラミングでは、複数のタスクを同時に実行できます。前のタスクが完了する前に、別のタスクに移動できます。

SpringBoot が非同期呼び出しをエレガントに実装する方法

Spring Boot では、@Async アノテーションを使用して非同期動作を実装できます。

実装手順

1. 非同期サービス インターフェイスを定義しますAsyncService.java

public interface AsyncService {

    void asyncMethod() throws InterruptedException;

    Future<String> futureMethod() throws InterruptedException;
}

2. 定義したインターフェイスを実装しますAsyncServiceImpl.java

@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService  {

    @Async
    @Override
    public void asyncMethod() throws InterruptedException {
        Thread.sleep(3000);
        log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName());
    }

    @Async
    @Override
    public Future<String> futureMethod() throws InterruptedException {
        Thread.sleep(5000);
        log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName());
        return new AsyncResult<>("task Done");
    }
}
  • AsyncServiceImpl は、spring 管理の bean です。

  • 非同期メソッドはパブリックであり、@Async アノテーションで修飾されている必要があります。

  • 戻り値の型は void または Future に制限されます。

3. コントローラーを定義するAsyncController.java

@EnableAsync
@RestController
@Slf4j
public class AsyncController {
    @Autowired
    AsyncService asyncService;

    @GetMapping("/async")
    public String asyncCallerMethod() throws InterruptedException {
        long start = System.currentTimeMillis();
        log.info("call async method, thread name: [{}]", Thread.currentThread().getName());
        asyncService.asyncMethod();
        String response = "task completes in :" +
                (System.currentTimeMillis() - start) + "milliseconds";
        return response;
    }

    @GetMapping("/asyncFuture")
    public String asyncFuture() throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();
        log.info("call async method, thread name: [{}]", Thread.currentThread().getName());
        Future<String> future = asyncService.futureMethod();
        // 阻塞获取结果
        String taskResult = future.get();
        String response = taskResult + "task completes in :" +
                (System.currentTimeMillis() - start) + "milliseconds";
        return response;
    }
}
  • 重要な点は、非同期を有効にするためにアノテーションを追加する必要があることです。 @EnableAsync 、もちろん、この注釈は他の場所に追加できます。

  • このインターフェイスが外部から呼び出される場合、asyncMethod() はデフォルトのタスク実行プログラムによって作成された別のスレッドによって実行され、メインスレッドは待つ必要がありません。非同期メソッドの実行が完了するまで。

4. 実行します

次に、実行して、非同期で返されるかどうかを確認してみましょう。

SpringBoot が非同期呼び出しをエレガントに実装する方法

SpringBoot が非同期呼び出しをエレガントに実装する方法

/async インターフェイスが呼び出され、最後のステップでメソッドが呼び出されることがわかります。 。

SpringBoot が非同期呼び出しをエレガントに実装する方法

SpringBoot が非同期呼び出しをエレガントに実装する方法

/asyncFuture を呼び出すと、戻り値が 5 秒を超えていることがわかります。これは非同期ではありませんか?実際、ログからわかるように、これも非同期ですが、返されるのは Future であり、Futrue.get() の呼び出しはブロックされます。

カスタマイズされた非同期タスク エグゼキューターと例外処理

次に、例外メソッドでエラーが報告された場合に何が起こるかを見てみましょう。非同期コードを次のように変更すると、ランタイム例外がスローされます。

SpringBoot が非同期呼び出しをエレガントに実装する方法

#次に示すように、非同期インターフェイスを再度実行すると、デフォルトのスレッド プールと例外処理が行われます。利用される。

SpringBoot が非同期呼び出しをエレガントに実装する方法

非同期メソッドの例外処理と非同期タスク エグゼキューターをカスタマイズすることもできます。次のコードに示すように、AsyncUncaughtExceptionHandler を構成する必要があります。 #

@Configuration
public class AsynConfiguration extends AsyncConfigurerSupport {
   @Override
   public Executor getAsyncExecutor() {
      ThreadPoolTaskExecutor executor = new 
                ThreadPoolTaskExecutor();
      executor.setCorePoolSize(3);
      executor.setMaxPoolSize(4);
      executor.setThreadNamePrefix("asyn-task-thread-");
      executor.setWaitForTasksToCompleteOnShutdown(true);
      executor.initialize();
      return executor;
  }
  @Override
  public AsyncUncaughtExceptionHandler  
         getAsyncUncaughtExceptionHandler() {
     return new AsyncUncaughtExceptionHandler() {
   
        @Override
        public void handleUncaughtException(Throwable ex, 
           Method method, Object... params) {
           System.out.println("Exception: " + ex.getMessage());
           System.out.println("Method Name: " + method.getName());
           ex.printStackTrace();
        }
    };
  }
}

もう一度実行すると、結果は次のようになります。

SpringBoot が非同期呼び出しをエレガントに実装する方法

@Async の仕組み

これは、

@EnableAsync を使用して行う必要があります。 アノテーション メイン アプリケーション クラス、または直接的または間接的な非同期メソッド呼び出し元クラスにアノテーションを付けて、非同期サポートを有効にします。主にプロキシ モードを通じて実装され、デフォルト モードは Proxy、もう 1 つは AspectJ です。プロキシ モードでは、プロキシ経由でのみ通話を傍受できます。非同期メソッドは、それが定義されているのと同じクラスから決して呼び出さないでください。機能しません。

メソッドに

@Async アノテーションを付けると、「proxyTargetClass」属性に基づいてオブジェクトのプロキシが作成されます。 spring がこのメソッドを実行すると、デフォルトで、関連するスレッド プール定義が検索されます。コンテキスト内で「taskExecutor」という名前が付けられている唯一の spring フレームワーク TaskExecutor Bean または Executor Bean。これらのどちらも解決できない場合は、デフォルトで Spring フレームワーク SimpleAsyncTaskExecutor が使用され、非同期メソッドの実行が処理されます。

以上がSpringBoot が非同期呼び出しをエレガントに実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。