使用SpringBoot实现可以动态调整的定时任务

  定时任务需求我们经常需要用到。在实现定时任务的场景中,一类是需要考虑到多节点只能由一个节点来执行的场景,这种定时任务需要能够将执行的记录存入到第三方存储中(比如数据库或者redis),实际的开发中是用一些定时任务的框架来完成(如quartz);另一类场景是每一个节点都能够执行的场景,不存在线程抢占的冲突。本文介绍的是适用于第二类场景,我们可以不用引入复杂的第三方框架,只用SpringBoot自带的方式来实现可以随时修改的定时任务。

1、实现cron表达式控制的定时任务

  实现用cron表达式的定时任务,我们可以用CronTrigger来实现,具体示例如下:

1.1 创建springboot项目,引入SpringBoot框架,pom.xml中的依赖如下

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <optional>true</optional>
        </dependency>
    </dependencies>

1.2 新建一个定时任务的配置的配置文件task-config.properties

task.cron.print-time=0/1 * * * * ?

1.3 编写SpringBoot的启动类

@EnableScheduling
@SpringBootApplication
public class SpringBootCronApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootCronApplication.class, args);
    }

}

1.4 编写定时任务的实现类,并加入到spring容器中

@Component
@Slf4j
@Data
@PropertySource("classpath:/task-config.properties")
public class CronScheduleTask implements SchedulingConfigurer {

    @Value("${task.cron.print-time}")
    private String cron;

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // 动态使用cron表达式配置定时任务
        taskRegistrar.addTriggerTask(() -> log.info(" current time : {}", LocalDateTime.now()), triggerContext -> {
            // 使用CronTrigger触发器,可以动态的修改cron表达式来操作循环规则
            CronTrigger cronTrigger = new CronTrigger(cron);
            return cronTrigger.nextExecutionTime(triggerContext);
        });
    }
}

1.5 编写controller,模拟用url来控制定时任务

@Slf4j
@RestController
@RequestMapping("/test")
@AllArgsConstructor
public class ScheduleController {

    private final CronScheduleTask cronScheduleTask;

    //private final TimerScheduleTask timerScheduleTask;

    @GetMapping("/updateCron")
    public String updateCron(@RequestParam("cron") String cron) {
        log.info("new cron : {}", cron);
        cronScheduleTask.setCron(cron);
        return "ok";
    }
}

1.6 启动项目,定时任务执行如下

2023-05-13 18:09:44.016  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:09:44.015
2023-05-13 18:09:45.013  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:09:45.013
2023-05-13 18:09:46.005  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:09:46.005
2023-05-13 18:09:47.001  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:09:47.001

我们可以看到,打印定时任务每1s执行一次,接下来我们用浏览器调用以下url,将打印任务设置成每5s执行一次
http://localhost:8080/test/updateCron?cron=0/5%20*%20*%20*%20*%20?
执行结果如下:

2023-05-13 18:12:54.319  INFO 50568 --- [io-8080-exec-10] c.e.s.controller.ScheduleController      : new cron : 0/5 * * * * ?
2023-05-13 18:12:54.319  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:12:54.319
2023-05-13 18:12:55.002  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:12:55.002
2023-05-13 18:13:00.006  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:13:00.006
2023-05-13 18:13:05.015  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:13:05.015
2023-05-13 18:13:10.002  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:13:10.002
2023-05-13 18:13:15.008  INFO 50568 --- [pool-1-thread-1] c.e.s.shcedule.CronScheduleTask          :  current time : 2023-05-13T18:13:15.008

从打印结果中我们可以看到,定时任务被成功设置为每5s执行一次。

2、 用间隔时间的方式实现每隔一定时间循环执行的定时任务

  有时候,我们只需要实现一个每隔一定的时间就执行一次的定时任务,这个时候我们可以借助PeriodicTrigger来实现,PeriodicTrigger参数的单位为毫秒(ms),代码如下:

2.1 在配置文件中新增一个间隔时间的默认配置

task.timer.print-time=1000

2.2 编写一个间隔时间的定时任务类,并加入到spring容器中

@Component
@Slf4j
@Data
@PropertySource("classpath:/task-config.properties")
public class TimerScheduleTask implements SchedulingConfigurer {

    @Value("${task.timer.print-time}")
    private Long timer;

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // 动态使用cron表达式配置定时任务
        taskRegistrar.addTriggerTask(() -> log.info("timer current time : {}", LocalDateTime.now()), triggerContext -> {
            // 使用循环时间的触发器,可以随意设置循环的时间间隔
            PeriodicTrigger periodicTrigger = new PeriodicTrigger(timer);
            return periodicTrigger.nextExecutionTime(triggerContext);
        });
    }
}

2.3 在controller中新增一个可以改变间隔时间的url调用方式

 @GetMapping("/updateTimer")
    public String updateCron(@RequestParam("timer") Long timer) {
        log.info("new timer : {}", timer);
        timerScheduleTask.setTimer(timer);
        return "ok";
    }

2.4 启动项目,执行定时任务如下

2023-05-13 18:21:07.666  INFO 41852 --- [pool-1-thread-1] c.e.s.shcedule.TimerScheduleTask         : timer current time : 2023-05-13T18:21:07.666
2023-05-13 18:21:08.681  INFO 41852 --- [pool-1-thread-1] c.e.s.shcedule.TimerScheduleTask         : timer current time : 2023-05-13T18:21:08.681
2023-05-13 18:21:09.690  INFO 41852 --- [pool-1-thread-1] c.e.s.shcedule.TimerScheduleTask         : timer current time : 2023-05-13T18:21:09.690
2023-05-13 18:21:10.702  INFO 41852 --- [pool-1-thread-1] c.e.s.shcedule.TimerScheduleTask         : timer current time : 2023-05-13T18:21:10.702

我们可以看到,打印的定时任务每1s执行一次,接下来我们调用以下的url,修改为每5s执行一次
http://localhost:8080/test/updateTimer?timer=5000
结果如下:

2023-05-13 18:22:56.130  INFO 41852 --- [nio-8080-exec-1] c.e.s.controller.ScheduleController      : new timer : 5000
2023-05-13 18:22:56.139  INFO 41852 --- [pool-1-thread-1] c.e.s.shcedule.TimerScheduleTask         : timer current time : 2023-05-13T18:22:56.139
2023-05-13 18:23:01.140  INFO 41852 --- [pool-1-thread-1] c.e.s.shcedule.TimerScheduleTask         : timer current time : 2023-05-13T18:23:01.140
2023-05-13 18:23:06.153  INFO 41852 --- [pool-1-thread-1] c.e.s.shcedule.TimerScheduleTask         : timer current time : 2023-05-13T18:23:06.153
2023-05-13 18:23:11.154  INFO 41852 --- [pool-1-thread-1] c.e.s.shcedule.TimerScheduleTask         : timer current time : 2023-05-13T18:23:11.154
2023-05-13 18:23:16.161  INFO 41852 --- [pool-1-thread-1] c.e.s.shcedule.TimerScheduleTask         : timer current time : 2023-05-13T18:23:16.161

从执行结果可以看出,定时任务顺利被修改为每5s执行一次


后记
  个人总结,欢迎转载、评论、批评指正

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于Quartz和Spring Boot结合实现动态管理定时任务,可以按照以下步骤进行操作: 1. 添加依赖:在Spring Boot项目的pom.xml文件中添加Quartz和Spring Boot的相关依赖。示例: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` 2. 创建定时任务类:编写一个实现Job接口的定时任务类,实现其中的execute方法,该方法定义了定时任务的具体逻辑。示例: ```java public class MyJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 执行定时任务逻辑 System.out.println("Hello, Quartz!"); } } ``` 3. 配置定时任务触发器:在Spring Boot的配置文件中配置定时任务的触发器。示例: ```yaml spring: quartz: job-store-type: memory properties: org: quartz: scheduler: instanceName: MyScheduler jobStore: useProperties: true threadPool: threadCount: 3 job-details: myJob: class: com.example.MyJob triggers: myTrigger: job-detail: myJob cron: "0/5 * * * * ?" ``` 4. 启用Quartz:在Spring Boot的启动类上添加@EnableScheduling注解,启用Quartz定时任务。示例: ```java @SpringBootApplication @EnableScheduling public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` 5. 动态管理定时任务:通过Quartz的API来实现动态添加、修改和删除定时任务的功能。可以在Service或Controller层调用Quartz的相关方法来实现。示例: ```java @Autowired private Scheduler scheduler; public void addJob(String jobName, String jobGroup, String cronExpression) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(MyJob.class) .withIdentity(jobName, jobGroup) .build(); Trigger trigger = TriggerBuilder.newTrigger() .withIdentity(jobName, jobGroup) .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) .build(); scheduler.scheduleJob(jobDetail, trigger); } public void updateJob(String jobName, String jobGroup, String cronExpression) throws SchedulerException { TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); trigger = trigger.getTriggerBuilder() .withIdentity(triggerKey) .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) .build(); scheduler.rescheduleJob(triggerKey, trigger); } public void deleteJob(String jobName, String jobGroup) throws SchedulerException { scheduler.deleteJob(JobKey.jobKey(jobName, jobGroup)); } ``` 以上就是使用Quartz和Spring Boot实现动态管理定时任务的基本步骤。您可以根据实际需求进行调整和扩展。希望能对您有所帮助!如果您还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值