ミドルウェアを使って非同期とかではなく、単にSpring Boot単体で非同期に実行する方法。以下の点を守ればOKなはず。
-
@Configuration
なクラスに@EnableAsync
アノテーションを付与 - 非同期実行用のスレッドをどう生成するかを定めるため、
Executor
を定義 - 非同期に実行したいメソッドに
@Async
アノテーションを付与
@Configuration
なクラスに@EnableAsync
アノテーションを付与
@EnableAsync
アノテーションがないと非同期実行できないため、必ず付与する。
@Configuration
@EnableAsync
class AsyncConfig {
// ...
}
@Configuration
なクラスなら何でも良いため、以下でもOK。
@SpringBootApplication
@EnableAsync
class SomeApplication
が、Executor
を定義するためにも専用の設定に切り出しておいた方が何かと便利だと思う。
非同期実行用のスレッドをどう生成するかを定めるため、Executor
を定義
デフォルトだと非同期実行をしようとするたびにスレッドを生成する仕様。スレッドプールなどを使用するには、そうなるよう定義を加える必要がある。
@Configuration
@EnableAsync
class AsyncConfig : AsyncConfigurerSupport() {
@Bean
override fun getAsyncExecutor(): Executor {
val executor = ThreadPoolTaskExecutor()
// initialize executor
return executor
}
}
非同期に実行したいメソッドに@Async
アノテーションを付与
そのまんま。
@Service
class SomeService {
@Async
fun execute() {
// ...
}
}
ちなみにクラス自体に@Async
アノテーションを付与すればメソッドすべてが非同期実行になる。
余談
動作確認のために超適当に以下のようなコードを書いたら非同期実行にならなくて困った。
@Controller
class SomeController {
@RequestMapping(/* ... */)
fun execute(): String {
// ...
val service = SomeService()
service.execute()
// ...
}
}
これはSomeService
のインスタンスを直接生成しているのが原因。普通は下記のようにDIコンテナ経由で取得するのが自然なはずなので、困ることないとは思うけど一応。私がSpring Bootに不慣れというのがバレバレだな!
@Controller
class SomeController(private val service: SomeService) {
@RequestMapping(/* ... */)
fun execute(): String {
// ...
service.execute()
// ...
}
}