Spring Bootで非同期処理を行う方法をメモしておきます。Spring Bootでは、非同期処理用のアノテーション@Async
が用意されているので、非同期処理が比較的簡単に実装できます。
環境
- Java 8 | |
- Gradle 6.0.1 | |
- Spring Boot 2.2.2.RELEASE |
Spring Bootで@Async
を使って非同期処理を行う方法
非同期処理を試すために、簡単なコマンドラインアプリケーションを作成してみます。Spring Bootでコマンドラインアプリケーションを作成する方法については、以下記事をご覧ください。
Spring Bootで簡単なコマンドラインアプリケーションを作成してみる - Reasonable Code
それではさっそく作っていきましょう。
build.gradle
については、特に非同期処理用のなにかを追加する必要はありません。
build.gradle
plugins { | |
id 'org.springframework.boot' version '2.2.2.RELEASE' | |
id 'io.spring.dependency-management' version '1.0.8.RELEASE' | |
id 'java' | |
} | |
group = 'com.example' | |
version = '0.0.1-SNAPSHOT' | |
sourceCompatibility = '1.8' | |
repositories { | |
mavenCentral() | |
} | |
dependencies { | |
implementation 'org.springframework.boot:spring-boot-starter' | |
testImplementation('org.springframework.boot:spring-boot-starter-test') { | |
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' | |
} | |
} | |
test { | |
useJUnitPlatform() | |
} |
スレッドプールの設定を行う
以下は非同期処理のスレッドプールの設定を行うクラス(AsyncConfig.java
)です。Bean登録して利用します。
AsyncConfig.java
@Configuration | |
public class AsyncConfig { | |
@Bean | |
public TaskExecutor taskExecutor() { | |
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); | |
// スレッドプール数 | |
executor.setCorePoolSize(10); | |
return executor; | |
} | |
} |
非同期処理を実装する
以下が非同期処理を行うクラス(DemoService.java
)です。非同期処理を行いたいクラスやメソッドに@Async
を付与します。簡単ですね。
戻り値のCompletableFuture
については、呼び出し元で非同期処理のハンドリング(非同期処理の戻り値を取得する、複数の非同期処理の待ち合わせを行う、など)を行うために利用します。もともとの戻り値をCompletableFuture
でラップしてあげればOKです。
DemoService.java
@Service | |
public class DemoService { | |
@Async | |
public CompletableFuture<Void> printName(final String name) throws InterruptedException { | |
System.out.println("print start: " + name); | |
Thread.sleep(1000); // 1秒待つ | |
System.out.println("print end: " + name); | |
return CompletableFuture.completedFuture(null); | |
} | |
} |
以下が非同期処理を呼び出すクラス(DemoApplication.java
)です。非同期処理を有効化するために、アプリケーションクラスに@EnableAsync
を付与します。以下の例だと、demoService.printName()
をそれぞれ非同期で呼び出しています。
DemoApplication.java
@SpringBootApplication | |
@EnableAsync | |
public class DemoApplication implements CommandLineRunner { | |
public static void main(String[] args) { | |
// .close()をつけないと非同期処理が完了してもアプリケーションが終了しない | |
SpringApplication.run(DemoApplication.class, args).close(); | |
} | |
private final DemoService demoService; | |
public DemoApplication(final DemoService demoService) { | |
this.demoService = demoService; | |
} | |
@Override | |
public void run(String... args) throws InterruptedException { | |
// それぞれ非同期で処理する | |
CompletableFuture<Void> name1 = demoService.printName("Alice"); | |
CompletableFuture<Void> name2 = demoService.printName("Bob"); | |
CompletableFuture<Void> name3 = demoService.printName("Chris"); | |
// 非同期処理が完了するまで待つ | |
CompletableFuture.allOf(name1, name2, name3).join(); | |
System.out.println("DONE!!!"); | |
} | |
} |
最後にアプリケーションを実行してみます。非同期で処理されているのがわかりますね。
$ ./gradlew bootRun | |
... | |
print start: Bob | |
print start: Chris | |
print start: Alice | |
print end: Alice | |
print end: Bob | |
print end: Chris | |
DONE!!! |
まとめ
Spring Bootで@Async
を使って非同期処理を行う方法でした。ポイントをまとめます。
- 非同期処理を行うクラスやメソッドに
@Async
を付与する - アプリケーションクラスに
@EnableAsync
を付与する CompletableFuture
を利用して非同期処理のハンドリングを行う- スレッドプールの設定クラスをBean登録する