SpringBoot 实现定时任务的两种方式
- 一、cron表达式语法
- 二、Scheduled注解使用
- 1、代码
- 2、效果
- 三、SchedulingConfigurer接口
- 1、代码
- 2、效果
- 四、进阶版基于接口SchedulingConfigurer的动态定时任务
- 1、代码
- 2、效果
一、cron表达式语法
cron表达式语法:[秒] [分] [小时] [日] [月] [周] [年]
序号 | 说明 | 是否必填 | 允许填写的值 | 允许的通配符 |
1 | 秒 | 是 | 0-59 | , - * / |
2 | 分 | 是 | 0-59 | , - * / |
3 | 小时 | 是 | 0-23 | , - * / |
4 | 日 | 是 | 1-31 | , - * ? / L W |
5 | 月 | 是 | 1-12 or JAN-DEC | , - * / |
6 | 周 | 是 | 1-7 or SUN-SAT | , - * ? / L # |
7 | 年 | 否 | empty 或 1970-2099 | , - * / |
常用通配符说明:
- 反斜线(/)字符表示增量值。例如,在秒字段中“5/15”代表从第 5 秒开始,每 15 秒一次。
- 星号()字符是通配字符,表示该字段可以接受任何可能的值(例如:在分的字段上设置 "",表示每一分钟都会触发)。
- 问号(?)问号表示这个字段不包含具体值。所以,如果指定月内日期,可以在月内日期字段中插入“?”,表示周内日期值无关紧要。字母 L 字符是 last 的缩写。放在月内日期字段中,表示安排在当月最后一天执行。在周内日期字段中,如果“L”单独存在,就等于“7”,否则代表当月内周内日期的最后一个实例。所以“0L”表示安排在当月的最后一个星期日执行。
- 横杠(-) 表示区间,例如 在小时上设置 “10-12”,表示 10,11,12点都会触发。
- 逗号(, ) 表示指定多个值,例如在周字段上设置 “MON,WED,FRI” 表示周一,周三和周五触发
- 井号(#)字符为给定月份指定具体的工作日实例。把“MON#2”放在周内日期字段中,表示把任务安排在当月的第二个星期一。
二、Scheduled注解使用
@Scheduled(fixedDelay = 5000) //上一次执行完毕时间点之后5秒再执行
@Scheduled(fixedDelayString = “5000”) //上一次执行完毕时间点之后5秒再执行
@Scheduled(fixedRate = 5000) //上一次开始执行时间点之后5秒再执行
@Scheduled(initialDelay=1000, fixedRate=5000) //第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
1、代码
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.time.LocalDateTime;
/**
* @author lichangyuan
* @create 2021-12-14 15:11
*/
//1.主要用于标记配置类
@Configuration
// 2.开启定时任务
@EnableScheduling
public class MySchedule {
//3.添加定时任务
@Scheduled(cron = "0/5 * * * * ?")
//或直接指定时间间隔,例如:5秒
//@Scheduled(fixedRate=5000)
private void configureTasks() {
System.err.println("基于注解(@Scheduled)的简单定时器demo: " + LocalDateTime.now());
}
}
2、效果
三、SchedulingConfigurer接口
这里核心的主要是使用到了ScheduledTaskRegistrar这个类有一个方法addTriggerTask(Runnable,Trigger) 两个参数,一个Runnable,一个是Trigger,在Runnable中执行业务逻辑代码,在Trigger修改定时任务的执行周期。
1、代码
//1.主要用于标记配置类
@Configuration
// 2.开启定时任务
@EnableScheduling
public class MySchedulingConfigurer implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//创建一个线程作为任务
taskRegistrar.addTriggerTask(new Runnable() {
@Override
public void run() {
System.err.println("基于接口(SchedulingConfigurer)的简单定时器demo: " + LocalDateTime.now());
}
//创建周期
}, new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
String cron = "0/6 * * * * ?";
CronTrigger trigger = new CronTrigger(cron);
return trigger.nextExecutionTime(triggerContext);
}
});
}
}
2、效果
四、进阶版基于接口SchedulingConfigurer的动态定时任务
1、代码
配置文件application.yml内容
#设置定时任务
#是否开启定时任务1
task.taskName1.switch=true
#任务表达式
task.taskName1.cron=0/5 * * * * ?
#是否开启定时任务2
task.taskName2.switch=true
#任务表达式
task.taskName2.cron=0/6 * * * * ?
配置类
/**
* @author lichangyuan
* @create 2021-12-14 15:47
*/
@Configuration
@EnableScheduling
public abstract class MySchedulingConfigurer2 implements SchedulingConfigurer {
/**
* @brief 定时任务周期表达式
*/
private String cron;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
//设置的线程池corePoolSize,自己根据业务需求设定
scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
scheduledTaskRegistrar.addTriggerTask(
//执行定时任务(Lambda 表达式)
() -> {
processTask();
},
//设置触发器(Lambda 表达式)
triggerContext -> {
// 初始化定时任务周期
if (StringUtils.isEmpty(cron)) {
cron = getCron();
}
CronTrigger trigger = new CronTrigger(cron);
return trigger.nextExecutionTime(triggerContext);
}
);
}
/**
* @brief 任务的处理函数
* 本函数需要由派生类根据业务逻辑来实现
*/
protected abstract void processTask();
/**
* @return String
* @brief 获取定时任务周期表达式
* 本函数由派生类实现,从配置文件,数据库等方式获取参数值
*/
protected abstract String getCron();
}
实现类1
/**
* @author lichangyuan
* @create 2021-12-14 15:47
*/
@Configuration
public class MySchedulingController1 extends MySchedulingConfigurer2 {
@Value(value = "${task.taskName1.switch}")
private Boolean isSwitch;
@Value(value = "${task.taskName1.cron}")
private String cron;
@Override
protected void processTask() {
if (isSwitch){
System.err.println("MySchedulingController1类基于接口(SchedulingConfigurer)的简单定时器demo: " + LocalDateTime.now());
}
}
@Override
protected String getCron() {
return cron;
}
}
实现类2
/**
* @author lichangyuan
* @create 2021-12-14 15:47
*/
@Configuration
public class MySchedulingController2 extends MySchedulingConfigurer2 {
@Value(value = "${task.taskName2.switch}")
private Boolean isSwitch;
@Value(value = "${task.taskName2.cron}")
private String cron;
@Override
protected void processTask() {
if (isSwitch){
System.err.println("MySchedulingController2类基于接口(SchedulingConfigurer)的简单定时器demo: " + LocalDateTime.now());
}
}
@Override
protected String getCron() {
return cron;
}
}
2、效果