Scheduledアノテーションを使うと、スケジュールされたタイミングでメソッドを実行することができます。 これで周期実行的なものは、簡単に実装できます。
実装方法
実行したいメソッドにScheduled
アノテーションを付けます。
@Component public class Scheduler { @Scheduled(fixedRate = 5000) public void doSomething() { // 5秒周期で行いたい処理 } }
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 {