【Java】Springで@Asyncを使わずに非同期化する方法

実行環境

@Asyncを使えないケース

  • 呼び出し元によって同期/非同期を選択したい
  • 対象メソッドのシグネチャを変えたくない/変えられない
    • 戻り値がある場合はFuture型に変更する必要がある

@Asyncを使わない非同期化方法

  1. Configurationクラスに@EnableAsyncを付与する
  2. Executorを定義する
  3. Executorをインジェクションする
  4. CompletableFutureのrunAsync/supplyAsyncで非同期化する

1. Configurationクラスに@EnableAsyncを付与する

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

SpringBootの場合はApplicationクラスでもOK

@EnableAsync
@SpringBootApplication
public class AsyncApplication {...}

2. Executorを定義する

Configuration(Application)クラスにExecutorのBeanを定義をする

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setThreadNamePrefix("TaskThread-");
        executor.initialize();
        return executor;
    }

3. ExecutorをDIする

4. CompletableFutureのsupplyAsync/runAsyncで非同期化する

@RestController
public class AsyncController {

    private final Service service;
    private final Executor executor;

    public AsyncController(Service service,
                                 @Qualifier("taskExecutor") Executor executor) {
        this.service= service;
        this.executor = executor;
    }

    @GetMapping("/")
    public String index() {
        CompletableFuture<String> cf =
                CompletableFuture.supplyAsync(() -> service.execute(), executor);
        try {
            String result = cf.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        return "";
    }

}

ポイントは以下

  • 定義したExecutorを@QualifierでDIする
  • DIしたExecutorをsupplyAsync/runAsyncの引数に指定する

参考文献

stmtk358.hatenablog.com