在spring boot项目中使用定时任务是很简单的啦,只要使用@EnableScheduling
和@Scheduled
两个注解就可以实现,然后借助cron表达式并且要先定义在配置文件中。
最近有两个新需求,现在这种简单使用@Scheduled
已经满足不了需求,一个是batch job是定时任务执行,需要在数据库配置cron表达式,来控制定时任务的执行时间。另一个是有个定时任务在线上是每天跑一次,但是在测试环境每天跑一次太耗时,需要我们修改更短的执行频率,下班前要把定时任务又改成和线上一样,所以要在spring boot实现动态定时任务,不然每改一次要提单重新部署一次,想想就想死…
下面用一个demo来实现下动态定时任务
因为只是个demo,只需要引入简单的依赖即可
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
启动类:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
定时任务配置文件,这里我们直接新建一个配置文件,定义两个cron表达式
task-config.ini
printTime.task1.cron=0/10 * * * * ?
printTime.task2.cron=0/15 * * * * ?
定时任务执行类
package com.example.demo.scheduler.dynamic;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@PropertySource("classpath:/task-config.ini")
public class ScheduleTask implements SchedulingConfigurer {
@Value("${printTime.task1.cron}")
private String task1cron;
@Value("${printTime.task2.cron}")
private String task2cron;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(() -> System.out.println("Task1 Current time: " + LocalDateTime.now()), triggerContext -> {
CronTrigger cronTrigger = new CronTrigger(task1cron);
return cronTrigger.nextExecutionTime(triggerContext);
});
taskRegistrar.addTriggerTask(() -> System.out.println("Task2 Current time: " + LocalDateTime.now()), triggerContext -> {
CronTrigger cronTrigger = new CronTrigger(task2cron);
return cronTrigger.nextExecutionTime(triggerContext);
});
}
public void setTask1cron(String task1cron) {
this.task1cron = task1cron;
}
public void setTask2cron(String task2cron) {
this.task2cron = task2cron;
}
}
定义一个接口,使得可以通过调用接口来动态修改定定时任务的执行时间
package com.example.demo.controller;
import com.example.demo.scheduler.dynamic.ScheduleTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/base")
public class BaseController {
private static final Logger logger = LoggerFactory.getLogger(BaseController.class);
@Resource
private ScheduleTask scheduleTask;
@GetMapping("/v1/cron/update")
public String updateCron(String cron, int task) {
logger.info("new cron: {}", cron);
if (task == 1) {
scheduleTask.setTask1cron(cron);
}
if (task == 2) {
scheduleTask.setTask2cron(cron);
}
return "ok";
}
}
接下来启动程序,可以看到Task1每10秒执行一次,Task2每15秒执行一次。
现在我们调用接口,把Task1修改为每15秒执行一次,Task2修改为每10秒一次。
curl http://localhost:8090/base/v1/cron/update?cron=0/15 * * * * ?&task=1
curl http://localhost:8090/base/v1/cron/update?cron=0/10 * * * * ?&task=2
可以看到定时任务执行时间发生了改变
另外,除了cron表达式,@Scheduled
还支持另一种触发条件,@Scheduled(fixedDelay = 10000L)
该触发条件可以随意设置循环间隔时间,动态定时任务同样也支持这种触发器。
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(() -> System.out.println("Task1 Current time: " + LocalDateTime.now()), triggerContext -> {
CronTrigger cronTrigger = new CronTrigger(task1cron);
return cronTrigger.nextExecutionTime(triggerContext);
});
taskRegistrar.addTriggerTask(() -> System.out.println("Task2 Current time: " + LocalDateTime.now()), triggerContext -> {
CronTrigger cronTrigger = new CronTrigger(task2cron);
return cronTrigger.nextExecutionTime(triggerContext);
});
// PeriodicTrigger
taskRegistrar.addTriggerTask(() -> System.out.println("Task3 Current time: " + LocalDateTime.now()), triggerContext -> {
PeriodicTrigger periodicTrigger = new PeriodicTrigger(10000L);
return periodicTrigger.nextExecutionTime(triggerContext);
});
}