同期プログラミング: 同期プログラミングでは、タスクは一度に 1 つずつ実行され、1 つのタスクが完了した場合にのみ、次のタスクのブロックが解除されます。 。
非同期プログラミング: 非同期プログラミングでは、複数のタスクを同時に実行できます。前のタスクが完了する前に、別のタスクに移動できます。
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. 実行します
次に、実行して、非同期で返されるかどうかを確認してみましょう。
/async
インターフェイスが呼び出され、最後のステップでメソッドが呼び出されることがわかります。 。
/asyncFuture
を呼び出すと、戻り値が 5 秒を超えていることがわかります。これは非同期ではありませんか?実際、ログからわかるように、これも非同期ですが、返されるのは Future
であり、Futrue.get()
の呼び出しはブロックされます。
次に、例外メソッドでエラーが報告された場合に何が起こるかを見てみましょう。非同期コードを次のように変更すると、ランタイム例外がスローされます。
#次に示すように、非同期インターフェイスを再度実行すると、デフォルトのスレッド プールと例外処理が行われます。利用される。
非同期メソッドの例外処理と非同期タスク エグゼキューターをカスタマイズすることもできます。次のコードに示すように、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(); } }; } }
@EnableAsync を使用して行う必要があります。 アノテーション メイン アプリケーション クラス、または直接的または間接的な非同期メソッド呼び出し元クラスにアノテーションを付けて、非同期サポートを有効にします。主にプロキシ モードを通じて実装され、デフォルト モードは
Proxy、もう 1 つは
AspectJ です。プロキシ モードでは、プロキシ経由でのみ通話を傍受できます。非同期メソッドは、それが定義されているのと同じクラスから決して呼び出さないでください。機能しません。
@Async アノテーションを付けると、「
proxyTargetClass」属性に基づいてオブジェクトのプロキシが作成されます。
spring がこのメソッドを実行すると、デフォルトで、関連するスレッド プール定義が検索されます。コンテキスト内で「
taskExecutor」という名前が付けられている唯一の
spring フレームワーク
TaskExecutor Bean または
Executor Bean。これらのどちらも解決できない場合は、デフォルトで Spring フレームワーク
SimpleAsyncTaskExecutor が使用され、非同期メソッドの実行が処理されます。
以上がSpringBoot が非同期呼び出しをエレガントに実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。