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