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 {