Spring Bootの@Scheduledの注意点

動作確認環境

  • Java 11
  • Spring Boot 2.2

JUnitで@Scheduledが起動してしまう

一定間隔でメソッドを実行してくれるSpring Bootの@ScheduledはJUnitでも起動することがわかった。

事実から見れば、@SpringBootTestでSpringが立ち上がっているのだから@Scheduledが実行されることは当たり前だとわかる。しかし、コードだけ見ていても、関係ないクラスのJUnitでも@Scheduledが密かに実行されていることは気づきにくいのではないか。

対策として、@Scheduledが付与されているメソッドを管理しているクラス(ここではscheduler/XxxScheduler.javaとする)に@Profileを付与して、ユニットテスト時に@Scheduledが動かないようにした。

ローカルPCでのJUnitの起動はJVMオプション-Dspring.profiles.active=local-testを設定していて、CI環境では-Dspring.profiles.active=ci-testを設定しているとする。どちらかが設定されていれば読み込まないようにする場合、@Profile("!local-test & !ci-test")とする。

@lombok.RequiredArgsConstructor
@Component
@Lazy(false) // 次で説明
@Profile("!local-test & !ci-test")
public class XxxScheduler {

    private final XxxService xxxService;

    @Scheduled(fixDelay = 1000 * 60) /* 1 min */
    void xxx() {
        xxxService.xxx();
    }
}

spring.main.lazy-initialization=true だと@Scheduledが起動しない

本番環境でspring.main.lazy-initialization=trueは設定しないだろうが、手元で開発するときはSpringの起動時間を少しでも短くするためにspring.main.lazy-initialization=trueを設定していることが多いだろう。この設定でアプリケーションの起動時ではなく、対象のBeanの呼び出し時にBeanが生成されるようになる。(Lazy Initialization)

Lazy Initializationだと、@Scheduledを含む@Componentが生成されないため、@Scheduledが起動しない。

対策としてクラスに@Lazy(false)を入れる。