之前写过文章记录怎么在SpringBoot项目中简单使用定时任务,不过由于要借助cron表达式且都提前定义好放在配置文件里,不能在项目运行中动态修改任务执行时间,实在不太灵活。
    经过网上搜索学习后,特此记录如何在SpringBoot项目中实现动态定时任务。
    因为只是一个demo,所以只引入了需要的依赖:

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframework.boot</groupId>
    4. <artifactId>spring-boot-starter-web</artifactId>
    5. </dependency>
    6. <dependency>
    7. <groupId>org.springframework.boot</groupId>
    8. <artifactId>spring-boot-starter-log4j2</artifactId>
    9. <optional>true</optional>
    10. </dependency>
    11. <!-- spring boot 2.3版本后,如果需要使用校验,需手动导入validation包-->
    12. <dependency>
    13. <groupId>org.springframework.boot</groupId>
    14. <artifactId>spring-boot-starter-validation</artifactId>
    15. </dependency>
    16. <dependency>
    17. <groupId>org.projectlombok</groupId>
    18. <artifactId>lombok</artifactId>
    19. <optional>true</optional>
    20. </dependency>
    21. </dependencies>

    启动类:

    1. package com.wl.demo;
    2. import org.springframework.boot.SpringApplication;
    3. import org.springframework.boot.autoconfigure.SpringBootApplication;
    4. import org.springframework.scheduling.annotation.EnableScheduling;
    5. /**
    6. * @author wl
    7. * @date 2022/3/22
    8. */
    9. @EnableScheduling
    10. @SpringBootApplication
    11. public class DemoApplication {
    12. public static void main(String[] args) {
    13. SpringApplication.run(DemoApplication.class, args);
    14. System.out.println("(*^▽^*)启动成功!!!(〃'▽'〃)");
    15. }
    16. }

    配置文件application.yml,只定义了服务端口:

    1. server:
    2. port: 8089

    定时任务执行时间配置文件:task-config.ini:

    printTime.cron=0/10 ?

    定时任务执行类:

    1. package com.wl.demo.task;
    2. import lombok.Data;
    3. import lombok.extern.slf4j.Slf4j;
    4. import org.springframework.beans.factory.annotation.Value;
    5. import org.springframework.context.annotation.PropertySource;
    6. import org.springframework.scheduling.Trigger;
    7. import org.springframework.scheduling.TriggerContext;
    8. import org.springframework.scheduling.annotation.SchedulingConfigurer;
    9. import org.springframework.scheduling.config.ScheduledTaskRegistrar;
    10. import org.springframework.scheduling.support.CronTrigger;
    11. import org.springframework.stereotype.Component;
    12. import java.time.LocalDateTime;
    13. import java.util.Date;
    14. /**
    15. * 定时任务
    16. * @author wl
    17. * @date 2022/3/22
    18. */
    19. @Data
    20. @Slf4j
    21. @Component
    22. @PropertySource("classpath:/task-config.ini")
    23. public class ScheduleTask implements SchedulingConfigurer {
    24. @Value("${printTime.cron}")
    25. private String cron;
    26. @Override
    27. public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
    28. // 动态使用cron表达式设置循环间隔
    29. taskRegistrar.addTriggerTask(new Runnable() {
    30. @Override
    31. public void run() {
    32. log.info("Current time: {}", LocalDateTime.now());
    33. }
    34. }, new Trigger() {
    35. @Override
    36. public Date nextExecutionTime(TriggerContext triggerContext) {
    37. // 使用CronTrigger触发器,可动态修改cron表达式来操作循环规则
    38. CronTrigger cronTrigger = new CronTrigger(cron);
    39. Date nextExecutionTime = cronTrigger.nextExecutionTime(triggerContext);
    40. return nextExecutionTime;
    41. }
    42. });
    43. }
    44. }

    编写一个接口,使得可以通过调用接口动态修改该定时任务的执行时间:

    1. package com.wl.demo.controller;
    2. import com.wl.demo.task.ScheduleTask;
    3. import lombok.extern.slf4j.Slf4j;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import org.springframework.web.bind.annotation.RequestMapping;
    7. import org.springframework.web.bind.annotation.RestController;
    8. /**
    9. * @author wl
    10. * @date 2022/3/22
    11. */
    12. @Slf4j
    13. @RestController
    14. @RequestMapping("/test")
    15. public class TestController {
    16. private final ScheduleTask scheduleTask;
    17. @Autowired
    18. public TestController(ScheduleTask scheduleTask) {
    19. this.scheduleTask = scheduleTask;
    20. }
    21. @GetMapping("/updateCron")
    22. public String updateCron(String cron) {
    23. log.info("new cron :{}", cron);
    24. scheduleTask.setCron(cron);
    25. return "ok";
    26. }
    27. }

    启动项目,可以看到任务每10秒执行一次:
    SpringBoot 设置动态定时任务 - 图1
    访问接口,传入请求参数cron表达式,将定时任务修改为15秒执行一次:
    SpringBoot 设置动态定时任务 - 图2
    可以看到任务变成了15秒执行一次
    SpringBoot 设置动态定时任务 - 图3
    除了上面的借助cron表达式的方法,还有另一种触发器,区别于CronTrigger触发器,该触发器可随意设置循环间隔时间,不像cron表达式只能定义小于等于间隔59秒。需要开通正版IDEA的可以加我微信:poxiaozhiai6,56元一年。

    1. package com.wl.demo.task;
    2. import lombok.Data;
    3. import lombok.extern.slf4j.Slf4j;
    4. import org.springframework.beans.factory.annotation.Value;
    5. import org.springframework.context.annotation.PropertySource;
    6. import org.springframework.scheduling.Trigger;
    7. import org.springframework.scheduling.TriggerContext;
    8. import org.springframework.scheduling.annotation.SchedulingConfigurer;
    9. import org.springframework.scheduling.config.ScheduledTaskRegistrar;
    10. import org.springframework.scheduling.support.CronTrigger;
    11. import org.springframework.scheduling.support.PeriodicTrigger;
    12. import org.springframework.stereotype.Component;
    13. import java.time.LocalDateTime;
    14. import java.util.Date;
    15. /**
    16. * 定时任务
    17. * @author wl
    18. * @date 2022/3/22
    19. */
    20. @Data
    21. @Slf4j
    22. @Component
    23. @PropertySource("classpath:/task-config.ini")
    24. public class ScheduleTask implements SchedulingConfigurer {
    25. @Value("${printTime.cron}")
    26. private String cron;
    27. private Long timer = 10000L;
    28. @Override
    29. public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
    30. // 动态使用cron表达式设置循环间隔
    31. taskRegistrar.addTriggerTask(new Runnable() {
    32. @Override
    33. public void run() {
    34. log.info("Current time: {}", LocalDateTime.now());
    35. }
    36. }, new Trigger() {
    37. @Override
    38. public Date nextExecutionTime(TriggerContext triggerContext) {
    39. // 使用CronTrigger触发器,可动态修改cron表达式来操作循环规则
    40. // CronTrigger cronTrigger = new CronTrigger(cron);
    41. // Date nextExecutionTime = cronTrigger.nextExecutionTime(triggerContext);
    42. // 使用不同的触发器,为设置循环时间的关键,区别于CronTrigger触发器,该触发器可随意设置循环间隔时间,单位为毫秒
    43. PeriodicTrigger periodicTrigger = new PeriodicTrigger(timer);
    44. Date nextExecutionTime = periodicTrigger.nextExecutionTime(triggerContext);
    45. return nextExecutionTime;
    46. }
    47. });
    48. }
    49. }

    增加一个修改时间的接口:

    1. package com.wl.demo.controller;
    2. import com.wl.demo.task.ScheduleTask;
    3. import lombok.extern.slf4j.Slf4j;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import org.springframework.web.bind.annotation.RequestMapping;
    7. import org.springframework.web.bind.annotation.RestController;
    8. /**
    9. * @author wl
    10. * @date 2022/3/22
    11. */
    12. @Slf4j
    13. @RestController
    14. @RequestMapping("/test")
    15. public class TestController {
    16. private final ScheduleTask scheduleTask;
    17. @Autowired
    18. public TestController(ScheduleTask scheduleTask) {
    19. this.scheduleTask = scheduleTask;
    20. }
    21. @GetMapping("/updateCron")
    22. public String updateCron(String cron) {
    23. log.info("new cron :{}", cron);
    24. scheduleTask.setCron(cron);
    25. return "ok";
    26. }
    27. @GetMapping("/updateTimer")
    28. public String updateTimer(Long timer) {
    29. log.info("new timer :{}", timer);
    30. scheduleTask.setTimer(timer);
    31. return "ok";
    32. }
    33. }

    测试结果:
    SpringBoot 设置动态定时任务 - 图4