Scheduledアノテーションを使うと、スケジュールされたタイミングでメソッドを実行することができます。
これで周期実行的なものは、簡単に実装できます。
実装方法
実行したいメソッドにScheduled
アノテーションを付けます。
@Component
public class Scheduler {
@Scheduled(fixedRate = 5000)
public void doSomething() {
}
}
Scheduled
アノテーションによる実行を有効とするためには、EableScheduling
アノテーションを付けます。
@SpringBootApplication
@EnableScheduling
public class SchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);
}
}
これだけで周期実行が実装できます。簡単ですね!
Scheduledで指定できるパターン
指定方法は大きく分けて3パターン用意されています。
fixedDelay
: 前回タスクの実行完了時点から指定時間後にタスクを実行する。単位はms。
fixedRate
: 前回タスクの実行開始時点から指定時間後にタスクを実行する。単位はms。
cron
: 指定した周期でタスクを実行する。(Linuxのcronと似た書式)
また、fixedDelay
とfixedRate
では、初回のタスクの実行開始時間を指定するものとして、initialDelay
があります。
下記のようにすると、初回はアプリケーション起動から30秒後に実行され、その次からは、前回タスクの実行完了から60秒後に実行されることになります。
@Scheduled(fixedDelay = 60000, initialDelay = 30000)
public void doSomething() {
}
cron
では、zone
というフィールドで、cronの起動時間のタイムゾーンを指定できます。(未指定の場合は、デフォルトのタイムゾーン)
下記のようにすると、東京のタイムゾーンで、8時と9時と10時に実行されます。(8時から10時の間で、0秒、0分のタイミングで実行といった指定になっている)
@Scheduled(cron = "0 0 8-10 * * *", zone = "Asia/Tokyo")
public void doSomething() {
}
設定ファイルで指定する
ソース上に固定値で設定するのではなく、設定ファイルに記載することができます。
${設定名}で指定しておいて、
@Scheduled(cron = "${scheduler.cron}")
public void doSomething() {
}
application.properties で設定値を書きます。
scheduler.cron=*/5 * * * * *
fixedDelay
、fixedRate
、initialDelay
も、設定値とできるように、fixedDelayString
、fixedRateString
、initialDelayString
というものがフィールドとしてあるので、そちらを使えばOKです。
@Scheduled(fixedRateString = "${scheduler.fixed-rate}")
public void doFixedRateString() throws InterruptedException {
}
ユニットテストの際に、周期実行を抑止する
テストの時には、勝手に周期実行が動いて欲しく無い場合もあるかと思います。
fixedDelayString
、fixedRateString
ならば、テスト時の設定値を変えてとても大きな数字にしておけば、抑止と同等のことができそうですが、cron
だと、ぜったいに実行されないタイミングを指定するのは難しそうです。
こういった場合は、EnableScheduling
が指定されないように設定してあげれば回避できます。
下記のようなクラスでSpring Bootを起動しているならば、
@SpringBootApplication
@EnableScheduling
public class SchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);
}
}
テスト用に別の起動クラスを作成し、そちらでは@EnableScheduling
を指定しないようにします。
また、コンポーネントスキャンで、@EnableScheduling
を指定しているものを拾ってしまうと有効になってしまうので、該当のクラスを除外するように指定しておきます。
@SpringBootApplication
@ComponentScan(excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, value = SchedulerApplication.class))
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
このクラスを@SpringBootTest
に指定してあげれば、@EnableScheduling
が指定されずに、周期実行を抑止することが出来ます。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SchedulerTest.TestApplication.class)
public class SchedulerTest {