定时任务Quartz : 就是在指定的时间执行一次或者循环执行,基本大部分项目都能用到这个, 还是很有用的。
本文代码地址:https://gitea.aiprose.com/nelson/sb_quartz
一、Quartz有四个核心概念:
1.Job:是一个接口,只定义一个方法 execute(JobExecutionContext context),在实现接口的 execute 方法中编写所需要定时执行的 Job(任务),JobExecutionContext 类提供了调度应用的一些信息;Job 运行时的信息保存在 JobDataMap 实例中。
2.JobDetail:Quartz 每次调度 Job 时,都重新创建一个 Job 实例,因此它不接受一个 Job 的实例,相反它接收一个 Job 实现类(JobDetail,描述 Job 的实现类及其他相关的静态信息,如 Job 名字、描述、关联监听器等信息),以便运行时通过 newInstance() 的反射机制实例化 Job。
3.Trigger:是一个类,描述触发 Job 执行的时间触发规则,主要有 SimpleTrigger 和 CronTrigger 这两个子类。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger 是最适合的选择;而 CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度方案:如工作日周一到周五的 15:00 ~ 16:00 执行调度等。
4.Scheduler:调度器就相当于一个容器,装载着任务和触发器,该类是一个接口,代表一个 Quartz 的独立运行容器,Trigger 和 JobDetail 可以注册到 Scheduler 中,两者在 Scheduler 中拥有各自的组及名称,组及名称是 Scheduler 查找定位容器中某一对象的依据,Trigger 的组及名称必须唯一,JobDetail 的组和名称也必须唯一(但可以和 Trigger 的组和名称相同,因为它们是不同类型的)。Scheduler 定义了多个接口方法,允许外部通过组及名称访问和控制容器中 Trigger 和 JobDetail。
二、准备环境
本文用的环境是gradle
1.添加依赖
//gradle
implementation 'org.springframework.boot:spring-boot-starter-quartz'
//maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2.启动类上添加注解
当然不加也可以
@EnableScheduling
3.自动启动任务
init方法中直接调用任务
这个案例很简单,就是启动一个定时任务,5秒后只执行一次。当然也可以多次循环执行
1.实现job
@Component
@Slf4j
public class DemoJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
log.info("执行时间:{}",new Date());
log.info("我要开始做具体的工作了");
}
}
2.配置Scheduler
@Component
@Slf4j
public class DemoScheduler {
@Resource
private Scheduler scheduler;
@PostConstruct
public void init() throws SchedulerException {
startTaskJob();
scheduler.start();
}
public void startTaskJob() throws SchedulerException {
String uuid = UUID.randomUUID().toString();
JobDetail jobDetail = JobBuilder.newJob(DemoJob.class).withIdentity(uuid).build();
Date currentTime = new Date();
log.info("配置时间:{}",currentTime);
Date nowTime = new Date();
nowTime.setTime(nowTime.getTime() + 5000l);
Trigger subsys = TriggerBuilder.newTrigger().withIdentity(uuid).startAt(nowTime).build();
//2分钟循环一次
//Trigger subsys = TriggerBuil
der.newTrigger().withIdentity(uuid).startAt(nowTime).withSchedule(SimpleScheduleBuilder.repeatHourlyForever().withIntervalInSeconds(2)).build();
scheduler.scheduleJob(jobDetail, subsys);
}
}
3.运行结果
5秒后执行了一次
1.实现Job
这次还将加入参数传递
这次是每隔6秒循环执行一次
@Component
@Slf4j
public class CronJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobKey key = context.getJobDetail().getKey();
log.info("task name: {}",key.getName());
JobDataMap jobDataMap = context.getTrigger().getJobDataMap(); //所有的参数都会在这个map里
log.info("传递的参数:name:{}",jobDataMap.get("name"));
log.info("我要开始做具体的工作了,{}",new Date());
}
}
2.配置Scheduler
使用usingJobData传递参数,支持多个参数,不限制数量。
@Component
@Slf4j
public class CronScheduler {
@Resource
private Scheduler scheduler;
@PostConstruct
public void init() throws SchedulerException {
startTaskJob();
scheduler.start();
}
private void startTaskJob() throws SchedulerException {
JobDetail jobDetail = JobBuilder.newJob(CronJob.class) .withIdentity("job1", "group1").build();
// 6的倍数秒执行 也就是 6 12 18 24 30 36 42 ....
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/6 * * * * ?");
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
.usingJobData("name","nelson").withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail,cronTrigger);
}
}
本文代码地址:https://gitea.aiprose.com/nelson/sb_quartz
cron一定有七位数,最后一位是年
第一位, 表示秒, 取值是0 ~ 59
第二位, 表示分. 取值是0 ~ 59
第三位, 表示小时, 取值是0 ~ 23
第四位, 表示天/日, 取值是0 ~ 31
第五位, 表示月份, 取值是1 ~ 12
第六位, 表示星期, 取值是1 ~ 7, 星期一,星期二…, 还有 1 表示星期日
第七位, 年份, 可以留空, 取值是1970 ~ 2099
cron中,还有一些特殊的符号,含义如下:
(*) 星号,可以理解为每的意思,每秒、每分、每天、每月、每年…。
(?)问号,问号只能出现在日期和星期这两个位置,表示这个位置的值不确定,每天 3 点执行,因此第六位星期的位置,是不需要关注的,就是不确定的值;同时,日期和星期是两个相互排斥的元素,通过问号来表明不指定值,比如 1 月 10 日是星期一,如果在星期的位置另指定星期二,就前后冲突矛盾了。
(-)减号,表达一个范围,如在小时字段中使用“10 - 12”,则表示从 10 到 12 点,即 10、11、12。
(,)逗号,表达一个列表值,如在星期字段中使用“1,2,4”,则表示星期一、星期二、星期四。
(/)斜杠,如 x/y,x 是开始值,y 是步长,比如在第一位(秒),0/15 就是从 0 秒开始,每隔 15 秒执行一次,最后就是 0、15、30、45、60,另 */y,等同于 0/y。
举几个例子熟悉一下:
0 0 3 * * ? :每天 3 点执行;
0 5 3 * * ?:每天 3 点 5 分执行;
0 5 3 ? * *:每天 3 点 5 分执行,与上面作用相同;
0 5/10 3 * * ?:每天 3 点的 5 分、15 分、25 分、35 分、45 分、55分这几个时间点执行;
0 10 3 ? * 1:每周星期天,3 点 10 分执行,注,1 表示星期天;
0 10 3 ? * 1#3:每个月的第三个星期,星期天执行,# 号只能出现在星期的位置。