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(fixedDelay = 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)
を入れる。