Quartz的使用
作者:互联网
Quartz的使用
1.初始Quartz
如果你的定时任务没有分布式需求,但需要对任务有一定的动态管理,例如任务的启动、暂停、恢复、停止和触发时间修改,那么Quartz非常适合你。
Quartz是Java定时任务领域一个非常优秀的框架,由OpenSymphony(一个开源组织)开发,这个框架进行了优良地解耦设计,整个模块可以分为三大部分:
-
Job:顾名思义,指待定时执行的具体工作内容;
-
Trigger:触发器,指定运行参数,包括运行次数、运行开始时间和技术时间、运行时长等;
-
Scheduler:调度器,将Job和Trigger组装起来,使定时任务被真正执行;
-
一个JobDetail(Job的实现类)可以绑定多个Trigger,但一个Trigger只能绑定一个JobDetail;
-
每个JobDetail和Trigger通过group和name来标识唯一性;
-
一个Scheduler可以调度多组JobDetail和Trigger。
2.Quartz基础使用
Quartz提供了丰富的API,下面我们在Springboot中使用Quartz完成一些简单的demo。
2.1 基于时间间隔的定时任务
基于时间间隔和时间长度实现定时任务,借助SimpleTrigger
,例如这个场景——每隔2s在控制台输出线程名和当前时间,持续30s。
1.导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2.新建Job,实现我们想要定时执行的任务:
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class SimpleJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) {
// 创建一个事件,下面仅创建一个输出语句作演示
System.out.println(Thread.currentThread().getName() + "--"
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));
}
}
3.创建Scheduler和Trigger,执行定时任务:
import org.junit.jupiter.api.Test;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SimpleQuartzTest {
/*
* 基于时间间隔的定时任务
*/
@Test
public void simpleTest() throws SchedulerException, InterruptedException {
// 1、创建Scheduler(调度器)
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 2、创建JobDetail实例,并与SimpleJob类绑定(Job执行内容)
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class)
.withIdentity("job1", "group1")
.build();
// 3、构建Trigger(触发器),定义执行频率和时长
Trigger trigger = TriggerBuilder.newTrigger()
// 指定group和name,这是唯一身份标识
.withIdentity("trigger-1", "trigger-group")
.startNow() //立即生效
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2) //每隔2s执行一次
.repeatForever()) // 永久执行
.build();
//4、将Job和Trigger交给Scheduler调度
scheduler.scheduleJob(jobDetail, trigger);
// 5、启动Scheduler
scheduler.start();
// 休眠,决定调度器运行时间,这里设置30s
TimeUnit.SECONDS.sleep(30);
// 关闭Scheduler
scheduler.shutdown();
}
}
启动测试方法后,控制台观察现象即可。注意到这么一句日志:Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
,这说明Scheduler
确实是内置了10个线程的线程池,通过打印线程名也印证了这一点。
$nbsp;
另外要尤其注意的是,我们之所以通过TimeUnit.SECONDS.sleep(30);设置休眠,是因为定时任务是交由线程池异步执行的,而测试方法运行结束,主线程随之结束导致定时任务也不再执行了,所以需要设置休眠hold住主线程。在真实项目中,项目的进程是一直存活的,因此不需要设置休眠时间。
2.2 基于Cron表达式的定时任务
基于Cron表达式的定时任务demo如下:
import org.junit.jupiter.api.Test;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.concurrent.TimeUnit;
public class SimpleQuartzTest {
/*
* 基于cron表达式的定时任务
*/
@Test
public void cronTest() throws SchedulerException, InterruptedException {
// 1、创建Scheduler(调度器)
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 2、创建JobDetail实例,并与SimpleJob类绑定
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class)
.withIdentity("job-1", "job-group").build();
// 3、构建Trigger(触发器),定义执行频率和时长
CronTrigger cronTrigger = TriggerBuilder.newTrigger()
.withIdentity("trigger-1", "trigger-group")
.startNow() //立即生效
// cronSchedule中单位是,秒,分,时,天,月,周,年,
.withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?"))
.build();
//4、执行
scheduler.scheduleJob(jobDetail, cronTrigger);
scheduler.start();
// 休眠,决定调度器运行时间,这里设置30s
TimeUnit.SECONDS.sleep(30);
// 关闭Scheduler
scheduler.shutdown();
}
}
3 Quartz解读
整个Quartz体系涉及的类及之间的关系如下图所示:
- JobDetail:
Job
接口的实现类,由JobBuilder
将具体定义任务的类包装而成。 - Trigger:触发器,定义定时任务的触发规则,包括执行间隔、时长等,使用
TriggerBuilder
创建,JobDetail
和Trigger
可以一对多,反之不可。触发器可以拥有多种状态。 - Scheduler:调度器,将
Job
和Trigger
组装起来,使定时任务被真正执行;是Quartz的核心,提供了大量API。 - JobDataMap:集成Map,通过键值对为
JobDetail
存储一些额外信息。 - JobStore:用来存储任务和触发器相关的信息,例如任务名称、数量、状态等等。Quartz 中有两种存储任务的方式,一种在在内存(
RAMJobStore
),一种是在数据库(JDBCJobStore
)。
3.1 Job
Job是一个接口,只有一个方法execute()
,我们创建具体的任务类时要继承Job并重写execute()
方法,使用JobBuilder
将具体任务类包装成一个JobDetail
(使用了建造者模式)交给Scheduler
管理。每个JobDetail
由name和group作为其唯一身份标识。
- JobDataMap中可以包含不限量的(序列化的)数据对象,在job实例执行的时候,可以使用其中的数据。
- JobDataMap继承Map,可通过键值对为JobDetail存储一些额外信息。
3.2 Trigger
Trigger有四类实现,分别如下:
- SimpleTrigger:简单触发器,支持定义任务执行的间隔时间,执行次数的规则有两种,一是定义重复次数,二是定义开始时间和结束时间。如果同时设置了结束时间与重复次数,先结束的会覆盖后结束的,以先结束的为准。
- CronTrigger:基于Cron表达式的触发器。
- CalendarIntervalTrigger:基于日历的触发器,比简单触发器更多时间单位,且能智能区分大小月和平闰年。
- DailyTimeIntervalTrigger:基于日期的触发器,如每天的某个时间段。
Trigger是有状态的:NONE
, NORMAL
, PAUSED
, COMPLETE
, ERROR
, BLOCKED
,状态之间转换关系:
COMPLETE
状态比较特殊,我在实际操作中发现,当Trigger长时间暂停后(具体时长不太确定)再恢复,状态就会变为COMPLETE,这种状态下无法再次启动该触发器。
3.3 Scheduler
调度器,是 Quartz 的指挥官,由 StdSchedulerFactory
产生,它是单例的。Scheduler中提供了 Quartz
中最重要的 API,默认是实现类是 StdScheduler
。
Scheduler中主要的API大概分为三种:
- 操作Scheduler本身:例如start、shutdown等;
- 操作Job:例如:addJob、pauseJob、pauseJobs、resumeJob、resumeJobs、getJobKeys、getJobDetail等
- 操作Trigger:例如pauseTrigger、resumeTrigger等
4 Quartz进阶使用
标签:Quartz,Job,Trigger,Scheduler,使用,import,JobDetail 来源: https://www.cnblogs.com/zjh0420/p/16693851.html