spring Task是spring boot中一个简单方便的定时任务
一:
在启动类Application.java中类上面加上@EnableScheduling开启定时任务,也可以启用异步:@EnableAsync
@EnableScheduling // 开启定时任务
@EnableAsync //开启异步
public class Application {
public static void main(String[] args) {
// 程序启动入口
// 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件
SpringApplication.run(Application.class,args);
}
}
二:
在controller层需要启用定时任务的方法上面加上@Scheduled注释
//@Scheduled(cron = "0/9 * * * * ? ")//定时9秒钟执行一次
//@Scheduled(cron = "0 5 14 * * ? ")//定时每天14:05执行
@Scheduled(cron = "0 0 9 * * ? ")//定时每天9点执行
public void testTask() throws Exception{
System.out.println("执行定时任务");
timingTaskService.timingTask();
}
@Scheduled注解
- @Scheduled(fixedRate = 5000) :上一次执行开始时间点之后5秒再执行
- @Scheduled(fixedDelay = 5000) :上一次执行完毕时间点之后5秒再执行
- @Scheduled(initialDelay=1000, fixedRate=5000) :第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次。initialDelay表示第一次调用前的延时,单位毫秒,必需配合cron、fixedDelay或者fixedRate来使用。
- @Scheduled(cron="*/5 * * * * *") :通过cron表达式定义规则,与fixedDelay类似,上次执行完毕后才进行下次调度。
定时任务串行执行的优先级
定义两个具有相同cron表达式的定时任务task01和task02,都是以固定时间间隔每1秒打印一次,看他们的输出是否会乱掉,如果每次都是任务1打印完再打印任务2,那就是固定优先级的,否则每次调度顺序是随机的。
@Scheduled(cron = "0/1 * * * * ?")
public void task01() throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " | task01 " + new Date().toLocaleString());
}
@Scheduled(cron = "0/1 * * * * ?")
public void task02() {
System.out.println(Thread.currentThread().getName() + " | task02 " + new Date().toLocaleString());
}
动态创建定时任务
使用注解的方式,无法实现动态的修改、添加或关闭定时任务,这个时候就需要使用编程的方式进行任务的更新操作了。可直接使用ThreadPoolTaskScheduler或者SchedulingConfigurer接口进行自定义定时任务创建。
1.SchedulingConfigurer
实现SchedulingConfigurer接口,重写configureTasks方法时添加定时任务:
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setTaskScheduler(taskScheduler());
taskRegistrar.getScheduler().schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "|SchedulingConfigurer cron task01");
}
}, new CronTrigger("0/3 * * * * ?"));
taskRegistrar.addCronTask(new CronTask(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "|SchedulingConfigurer cron task02");
}
}, new CronTrigger("0/2 * * * * ?")));
}
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(10);
taskScheduler.setThreadNamePrefix("spring-task-scheduler-thread-");
taskScheduler.setAwaitTerminationSeconds(60);
taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
taskScheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
return taskScheduler;
}
}
2.ThreadPoolTaskScheduler
ThreadPoolTaskScheduler是Spring Task的核心实现类,该类提供了大量的重载方法进行任务调度。首先配置一个自定义任务调度线程池ThreadPoolTaskScheduler,可参考上面ScheduleConfig中的配置,这里不再赘述。
编写一个控制层实现定时任务的动态创建、关闭以及修改:
@Slf4j
@RestController
@RequestMapping("/task")
public class DynamicTaskController {
@Resource
private ThreadPoolTaskScheduler taskScheduler;
private ScheduledFuture<?> scheduledFuture;
@Value("${timing-task.cron1}")
private String cronStr1;
@Value("${timing-task.cron2}")
private String cronStr2;
@RequestMapping("/start")
public String startTask() {
scheduledFuture = taskScheduler.schedule(new RunTask01(), new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
return new CronTrigger(cronStr1).nextExecutionTime(triggerContext);
}
});
log.info("start timed task success ..");
return "start task suceess";
}
@RequestMapping("/stop")
public String stopTask() {
Boolean result = null;
if (scheduledFuture != null) {
result = scheduledFuture.cancel(true);
}
log.info("stop timed task result: " + result);
return "stop task result: " + result;
}
@RequestMapping("/modify")
public String modifyTask() {
Boolean stopResult = null;
// 停止定时任务
if (scheduledFuture != null) {
stopResult = scheduledFuture.cancel(true);
} else {
log.info("modify task error -> scheduledFuture is null");
return "error";
}
// 更换cron重新开启定时任务
if (stopResult) {
scheduledFuture = taskScheduler.schedule(new RunTask01(), new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
return new CronTrigger(cronStr2).nextExecutionTime(triggerContext);
}
});
log.info("modify task success ..");
return "success";
}
log.info("modify task failed ..");
return "failed";
}
class RunTask01 implements Runnable {
@Override
public void run() {
log.info(Thread.currentThread().getName() + "|schedule task01" + "|" + new Date().toLocaleString());
}
}
class RunTask02 implements Runnable {
@Override
public void run() {
log.info(Thread.currentThread().getName() + "|schedule task02" + "|" + new Date().toLocaleString());
}
}
}
3.配置文件中定义cron表达式:
timing-task.cron1=0/1 * * * * ?
timing-task.cron2=0/5 * * * * ?
通过这种编程式的定时任务优点是灵活可拓展,缺点是不能与异步调用相结合,例如@Async注解。
ThreadPoolTaskScheduler 除了提供了schedule()还有其他方法设置定时任务,简单示例如下:
@RequestMapping("/test")
public String test(){
Date startTime = new Date();// 起始时间点
long period = 1000, delay = 2000;// 时间间隔,毫秒
// 从指定时间点开始以固定频率执行定时任务,类似于@Scheduled(fixedRate = 1000, initialDelay=0)
taskScheduler.scheduleAtFixedRate(new RunTask01(), startTime, period);
// 从指定时间点开始以固定时间间隔执行定时任务,类似于@Scheduled(fixedDelay = 2000, initialDelay=0)
taskScheduler.scheduleWithFixedDelay(new RunTask02(), startTime, delay);
return "done";
}