Quartz简介
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。
quartz是开源且具有丰富特性的"任务调度库",能够集成于任何的java应用,小到独立的应用,大至电子商业系统。quartz能够创建亦简单亦复杂的调度,以执行上十、上百,甚至上万的任务。任务job被定义为标准的java组件,能够执行任何你想要实现的功能。quartz调度框架包含许多企业级的特性,如JTA事务、集群的支持。
简而言之,quartz就是基于java实现的任务调度框架,用于执行你想要执行的任何任务。
官网:http://www.quartz-scheduler.org/
Quartz体系结构
jobdetail和trigger的关系是1对n
Quartz常用API
以下是Quartz编程API几个重要接口,也是Quartz的重要组件
- Scheduler:用于与调度程序交互的主程序接口。通过Scheduler来绑定jobdetail和trigger。只有安排进执行计划的任务Job(通过scheduler.scheduleJob方法安排进执行计划),当它预先定义的执行时间到了的时候(任务触发trigger),该任务才会执行。
- Job:预先定义的任务逻辑。
- JobDetail:定时任务的实例,JobDetail实例是通过JobBuilder类创建的,Scheduler真正调度的是JobDetail而不是job。
- JobDataMap:可以包含不限量的(序列化的)数据对象,可以看作JobDetail内业务逻辑运行时的需要的一系列参数。
- Trigger :触发器,Trigger对象是用来触发执行Job的。当调度一个job时,我们实例一个触发器然后调整它的属性来满足job执行的条件。表明任务在什么时候会执行。定义了一个已经被安排的任务将会在什么时候执行的时间条件,比如每2秒就执行一次。
- JobBuilder :用于声明一个任务实例,也可以定义关于该任务的详情比如任务名、组名等,这个声明的实例将会作为一个实际执行的任务。
- TriggerBuilder :用于声明触发器trigger实例。
- JobListener、TriggerListener、SchedulerListener:监听器,用于对组件的监听。
- ......
两个重要注解
@DisallowConcurrentExecution
作用:禁止同一任务定义的多个实例并发执行,确保任务在前一次执行完成后才会触发下一次执行。
解释:一个定时任务5秒钟触发一次,执行一次需要10分钟。打上这个注解后,在打上这个注解后,在上一个任务执行结束前,即使已经到了它的执行时间,也要等待上一个任务执行结束。
@PersistJobDataAfterExecution
作用:在执行完成后持久化JobDataMap中的数据,使任务状态可以在多次执行间保持。
解释:在任务中修改JobDataMap中的数据,此番修改是永久有效的。
案例
入门案例
新建一个springboot项目,导入quartz依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
写一个HelloJob任务类实现Job接口,重写execute方法
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 定义时间
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = dateFormat.format(date);
System.out.println("进行数据库备份操作。当前任务执行的时间:" + dateString);
}
}
声明JobDetail指定HelloJob,声明Trigger,绑定它俩交给Scheduler调度
public class HelloSchedulerDemo {
public static void main(String[] args) throws Exception {
// 1:从工厂中获取任务调度的实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1") // 定义该实例唯一标识
.build();
// 3:定义触发器 ,马上执行, 然后每5秒重复执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 定义该实例唯一标识
.startNow() // 马上执行
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.repeatSecondlyForever(5)) // 简单间隔触发,每5秒执行一次
.build();
// 4:使用触发器调度任务的执行
scheduler.scheduleJob(job, trigger);
// 5:开启
scheduler.start();
// 关闭
// scheduler.shutdown();
}
}
使用JobDataMap
当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法。Job能通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据。当然,JobDataMap也在JobExecutionContext里面。
JobDataMap里面的值的获取方式
(1)使用Map获取。
- 在进行任务调度时,JobDataMap存储在JobExecutionContext中 ,非常方便获取。
- JobDataMap可以用来装载任何可序列化的数据对象,当job实例对象被执行时这些参数对象会传递给它。
- JobDataMap实现了JDK的Map接口,并且添加了非常方便的方法用来存取基本数据类型。
(2)Job实现类中添加setter方法对应JobDataMap的键值,Quartz框架默认的JobFactory实现类在初始化job实例对象时会自动地调用这些setter方法。
@PersistJobDataAfterExecution
public class HelloJob implements Job {
private String name;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Hello, " + name + "!");
setName("I have changed my name");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 定义时间
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = dateFormat.format(date);
// 定义工作任务内容
System.out.println("进行数据库备份操作。当前任务执行的时间:" + dateString);
System.out.println("name from job detail:"+jobExecutionContext.getJobDetail().getJobDataMap().get("name"));
System.out.println("name from trigger:" + jobExecutionContext.getTrigger().getJobDataMap().get("name"));
System.out.println("name from merge:" + jobExecutionContext.getMergedJobDataMap().get("name"));
System.out.println("age:"+jobExecutionContext.getJobDetail().getJobDataMap().get("age"));
}
}
public class HelloSchedulerDemo {
public static void main(String[] args) throws Exception {
// 1:从工厂中获取任务调度的实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1") // 定义该实例唯一标识
.usingJobData("name","cjj")
.usingJobData("age",18)
.build();
// 3:定义触发器 ,马上执行, 然后每5秒重复执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 定义该实例唯一标识
.startNow() // 马上执行
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.repeatSecondlyForever(5)) // 简单间隔触发,每5秒执行一次
.usingJobData("name","hlyy")
.build();
// 4:使用触发器调度任务的执行
scheduler.scheduleJob(job, trigger);
// 5:开启
scheduler.start();
// 关闭
// scheduler.shutdown();
}
}
输出如下
进行数据库备份操作。当前任务执行的时间:2025-04-25 14:46:39
name from job detail:cjj
name from trigger:hlyy
name from merge:hlyy
age:18
这里注意:如果遇到同名的key,Trigger的优先级更高
有状态的Job
@PersistJobDataAfterExecution
public class HelloJob implements Job {
private int count;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 定义时间
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = dateFormat.format(date);
// 定义工作任务内容
System.out.println("进行数据库备份操作。当前任务执行的时间:" + dateString + " 执行第 " + (++count) + " 次");
// 保存到JobDataMap中
jobExecutionContext.getJobDetail().getJobDataMap().put("count", count);
}
public void setCount(int count) {
this.count = count;
}
}
注意加上@PersistJobDataAfterExecution注解,才会每次保存count的状态,否则每次该JobDetail被调度时,都会将count初始化为0
public class HelloSchedulerDemo {
public static void main(String[] args) throws Exception {
// 1:从工厂中获取任务调度的实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1") // 定义该实例唯一标识
.usingJobData("count",0)
.build();
// 3:定义触发器 ,马上执行, 然后每5秒重复执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 定义该实例唯一标识
.startNow() // 马上执行
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.repeatSecondlyForever(5)) // 简单间隔触发,每5秒执行一次
.build();
// 4:使用触发器调度任务的执行
scheduler.scheduleJob(job, trigger);
// 5:开启
scheduler.start();
// 关闭
// scheduler.shutdown();
}
}
4:54:32.523 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job group1.job1
进行数据库备份操作。当前任务执行的时间:2025-04-25 14:54:32 执行第 1 次
14:54:37.524 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'group1.job1', class=org.daolong.job.HelloJob
14:54:37.525 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
14:54:37.525 [DefaultQuartzScheduler_Worker-2] DEBUG org.quartz.core.JobRunShell - Calling execute on job group1.job1
进行数据库备份操作。当前任务执行的时间:2025-04-25 14:54:37 执行第 2 次
14:54:42.517 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'group1.job1', class=org.daolong.job.HelloJob
14:54:42.518 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
14:54:42.518 [DefaultQuartzScheduler_Worker-3] DEBUG org.quartz.core.JobRunShell - Calling execute on job group1.job1
进行数据库备份操作。当前任务执行的时间:2025-04-25 14:54:42 执行第 3 次
Cron触发器
public class HelloSchedulerDemoCronTrigger {
public static void main(String[] args) throws Exception {
// 1:从工厂中获取任务调度的实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1") // 定义该实例唯一标识
.build();
// 3:定义触发器 ,马上执行, 然后每5秒重复执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 定义该实例唯一标识
.withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?")) // 每5秒执行一次
.build();
// 4:使用触发器调度任务的执行
scheduler.scheduleJob(job, trigger);
// 5:开启
scheduler.start();
// 关闭
// scheduler.shutdown();
}
}
监听器(以SchedulerListener为例)
自定义一个MySchedulerListener实现SchedulerListener接口
public class MySchedulerListener implements SchedulerListener {
@Override
public void jobScheduled(Trigger trigger) {
String jobName = trigger.getJobKey().getName();
System.out.println(jobName + " 完成部署");
}
@Override
public void jobUnscheduled(TriggerKey triggerKey) {
System.out.println(triggerKey + " 完成卸载");
}
@Override
public void triggerFinalized(Trigger trigger) {
System.out.println("触发器被移除 " + trigger.getJobKey().getName());
}
@Override
public void triggerPaused(TriggerKey triggerKey) {
System.out.println(triggerKey + " 正在被暂停");
}
@Override
public void triggersPaused(String triggerGroup) {
System.out.println("触发器组 "+triggerGroup + " 正在被暂停");
}
@Override
public void triggerResumed(TriggerKey triggerKey) {
System.out.println(triggerKey + " 正在从暂停中恢复");
}
@Override
public void triggersResumed(String triggerGroup) {
System.out.println("触发器组 "+triggerGroup + " 正在从暂停中恢复");
}
@Override
public void jobAdded(JobDetail jobDetail) {
System.out.println(jobDetail.getKey()+" 添加工作任务");
}
@Override
public void jobDeleted(JobKey jobKey) {
System.out.println(jobKey+" 删除工作任务");
}
@Override
public void jobPaused(JobKey jobKey) {
System.out.println(jobKey+" 工作任务正在被暂停");
}
@Override
public void jobsPaused(String jobGroup) {
System.out.println("工作任务组 "+jobGroup+" 正在被暂停");
}
@Override
public void jobResumed(JobKey jobKey) {
System.out.println(jobKey+" 正在从暂停中恢复");
}
@Override
public void jobsResumed(String jobGroup) {
System.out.println("工作任务组 "+jobGroup+" 正在从暂停中恢复");
}
@Override
public void schedulerError(String msg, SchedulerException cause) {
System.out.println("产生严重错误时调用: "+msg+" "+cause.getUnderlyingException());
}
@Override
public void schedulerInStandbyMode() {
System.out.println("调度器在挂起模式下调用");
}
@Override
public void schedulerStarted() {
System.out.println("调度器 开启时调用");
}
@Override
public void schedulerStarting() {
System.out.println("调度器 正在开启时调用");
}
@Override
public void schedulerShutdown() {
System.out.println("调度器 已经被关闭 时调用");
}
@Override
public void schedulerShuttingdown() {
System.out.println("调度器 正在被关闭 时调用");
}
@Override
public void schedulingDataCleared() {
System.out.println("调度器的数据被清除时调用");
}
}
public class HelloSchedulerDemoSchedulerListener {
public static void main(String[] args) throws Exception {
// 1:从工厂中获取任务调度的实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1") // 定义该实例唯一标识
.build();
// 3:定义触发器 ,马上执行, 然后每5秒重复执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 定义该实例唯一标识
.startNow() // 马上执行
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.repeatSecondlyForever(5)) // 每5秒执行一次
.build();
// 4:使用触发器调度任务的执行
scheduler.scheduleJob(job, trigger);
// 创建SchedulerListener
scheduler.getListenerManager().addSchedulerListener(new MySchedulerListener());
// 移除对应的SchedulerListener
// scheduler.getListenerManager().removeSchedulerListener(new MySchedulerListener());
// 5:开启
scheduler.start();
// 延迟7秒后关闭
Thread.sleep(7000);
// 关闭
scheduler.shutdown();
}
}
SpringBoot整合Quartz,实现一个Quartz任务调度中心
参考文章:Spring Boot整合Quartz实现动态配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 兼容 Spring Boot 2.6.x 的版本 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- 美化ui-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<!-- 校验框架-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
# MySQL 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/quartz_db?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Quartz 持久化配置
spring.quartz.job-store-type=jdbc
# 启动时不初始化数据库,我们自己手动初始化过了
spring.quartz.jdbc.initialize-schema=embedded
# Quartz 集群配置
#spring.quartz.properties.org.quartz.jobStore.isClustered: true
#spring.quartz.properties.org.quartz.jobStore.tablePrefix: QRTZ_
#spring.quartz.properties.org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
在maven的依赖包下找到Quartz 调度器所需的表结构的 SQL 脚本文件,到数据库中手动执行。
E:\apache-maven-3.8.6\repository\org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar!\org\quartz\impl\jdbcjobstore\tables_mysql_innodb.sql
@Configuration
public class QuartzConfig {
@Bean
public Scheduler myScheduler(SchedulerFactoryBean schedulerFactoryBean) throws Exception {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduler.start();
scheduler.getListenerManager().addJobListener(new MyJobListener());
return scheduler;
}
}
@Component
public class QuartzTestJob extends QuartzJobBean {
@Override
protected void executeInternal(org.quartz.JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Quartz Test Job");
}
}
public interface QuartzService {
/**
* 添加定时任务
*/
void addJob(QuartzCreateParam param) throws SchedulerException;
/**
* 修改定时任务
*/
void updateJob(QuartzUpdateParam param) throws SchedulerException;
/**
* 暂停定时任务
*/
void pauseJob(QuartzDetailParam param) throws SchedulerException;
/**
* 恢复定时任务
*/
void resumeJob(QuartzDetailParam param) throws SchedulerException;
/**
* 删除定时任务
*/
void deleteJob(QuartzDetailParam param) throws SchedulerException;
/**
* 定时任务列表
* @return
*/
List<QuartzJobDetailDto> jobList() throws SchedulerException;
/**
* 定时任务详情
*/
QuartzJobDetailDto jobDetail(QuartzDetailParam param) throws SchedulerException;
}
@Service
public class QuartzServiceImpl implements QuartzService {
@Resource(name = "myScheduler")
private Scheduler scheduler;
@Override
public void addJob(QuartzCreateParam param) throws SchedulerException {
String clazzName = param.getJobClazz();
String jobName = param.getJobName();
String jobGroup = param.getJobGroup();
String triggerName = param.getTriggerName();
String triggerGroup = param.getTriggerGroup();
String cron = param.getCron();
String description = param.getDescription();
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
if (checkExist(jobKey)) {
throw new BaseException("要添加的任务已经存在:" + jobKey);
}
Class<? extends Job> jobClass = null;
try {
jobClass = (Class<? extends Job>) Class.forName(clazzName);
} catch (ClassNotFoundException e) {
throw new BaseException("找不到任务类:" + clazzName);
}
JobDataMap jobDataMap = new JobDataMap();
if (param.getJobDataMap() != null) {
jobDataMap.putAll(param.getJobDataMap());
}
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobName, jobGroup)
.usingJobData(jobDataMap)
.build();
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
Trigger trigger = TriggerBuilder.newTrigger()
.withSchedule(scheduleBuilder)
.withIdentity(TriggerKey.triggerKey(triggerGroup, triggerName))
.withDescription(description)
.build();
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start();
}
}
/**
* 可能出现的情况
* 1.修改该任务现指定的触发器的cron表达式 (给出triggerName、triggerGroup、cron)
* 2.为该任务绑定一个新的(新增)触发器 (给出triggerName、triggerGroup、cron)
* 3.为该任务绑定一个已有触发器 (给出triggerName、triggerGroup)
*/
@Override
public void updateJob(QuartzUpdateParam param) throws SchedulerException {
String jobName = param.getJobName();
String jobGroup = param.getJobGroup();
String triggerName = param.getTriggerName();
String triggerGroup = param.getTriggerGroup();
String cron = param.getCron();
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
if (!checkExist(jobKey)) {
throw new BaseException("要修改的任务不存在:" + jobKey);
}
// 情况3
if (cron.isEmpty()) {
if (!checkExist(triggerKey)) {
throw new BaseException("要绑定的任务触发器不存在:" + triggerKey);
}
scheduler.scheduleJob(scheduler.getTrigger(triggerKey));
return;
}
// 情况1
if (checkExist(triggerKey)) {
// 获取原触发器的状态
Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
Trigger trigger = TriggerBuilder.newTrigger()
.withSchedule(scheduleBuilder)
.withIdentity(triggerKey).build();
/** 更新触发器
* 停止旧触发器的调度计划。
* 将新触发器绑定到原任务(JobDetail)。
* 根据新触发器的配置(如 Cron 表达式、开始/结束时间)生成下一次触发时间。
* 根据原触发器的状态选择是否继续调度。
*/
scheduler.rescheduleJob(triggerKey, trigger);
if (triggerState == Trigger.TriggerState.PAUSED) {
scheduler.pauseTrigger(triggerKey);
}
return;
}
// 情况2
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
Trigger trigger = TriggerBuilder.newTrigger()
.withSchedule(scheduleBuilder)
.withIdentity(triggerKey).build();
scheduler.scheduleJob(trigger);
}
@Override
public void pauseJob(QuartzDetailParam param) throws SchedulerException {
String jobName = param.getJobName();
String jobGroup = param.getJobGroup();
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
if (checkExist(jobKey)) {
scheduler.pauseJob(jobKey);
} else {
throw new BaseException("要暂停的任务不存在:" + jobKey);
}
}
@Override
public void resumeJob(QuartzDetailParam param) throws SchedulerException {
String jobName = param.getJobName();
String jobGroup = param.getJobGroup();
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
if (checkExist(jobKey)) {
if (!scheduler.isShutdown()) {
scheduler.resumeJob(jobKey);
return;
}
}
throw new BaseException("要恢复的任务不存在:" + jobKey);
}
@Override
public void deleteJob(QuartzDetailParam param) throws SchedulerException {
String jobName = param.getJobName();
String jobGroup = param.getJobGroup();
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
if (!checkExist(jobKey)) {
throw new BaseException("要删除的任务不存在:" + jobKey);
}
// 先暂停再删除
scheduler.pauseJob(jobKey);
scheduler.deleteJob(jobKey);
}
@Override
public List<QuartzJobDetailDto> jobList() throws SchedulerException {
// 获取匹配所有任务的matcher
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
List<QuartzJobDetailDto> jobDtoList = new ArrayList<>();
Set<JobKey> jobKeySet = scheduler.getJobKeys(matcher);
for (JobKey jobKey : jobKeySet) {
QuartzJobDetailDto jobDto = getJobDtoByJobKey(jobKey);
jobDtoList.add(jobDto);
}
return jobDtoList;
}
@Override
public QuartzJobDetailDto jobDetail(QuartzDetailParam param) throws SchedulerException {
String jobName = param.getJobName();
String jobGroup = param.getJobGroup();
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
return getJobDtoByJobKey(jobKey);
}
// 检查任务是否存在, 如果存在返回true
private Boolean checkExist(JobKey jobKey) throws SchedulerException {
return scheduler.checkExists(jobKey);
}
// 检查触发器是否存在, 如果存在返回true
private Boolean checkExist(TriggerKey triggerKey) throws SchedulerException {
return scheduler.checkExists(triggerKey);
}
// 根据jobKey获取任务详情
public QuartzJobDetailDto getJobDtoByJobKey(JobKey jobKey) throws SchedulerException {
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
List<Trigger> triggerList = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
QuartzJobDetailDto jobDto = new QuartzJobDetailDto();
jobDto.setJobClazz(jobDetail.getJobClass().toString());
jobDto.setJobName(jobKey.getName());
jobDto.setJobGroup(jobKey.getGroup());
jobDto.setJobDataMap(jobDetail.getJobDataMap());
List<QuartzTriggerDetailDto> triggerDtoList = new ArrayList<>();
for (Trigger trigger : triggerList) {
QuartzTriggerDetailDto triggerDto = new QuartzTriggerDetailDto();
triggerDto.setTriggerName(trigger.getKey().getName());
triggerDto.setTriggerGroup(trigger.getKey().getGroup());
triggerDto.setDescription(trigger.getDescription());
if (trigger instanceof CronTriggerImpl) {
CronTriggerImpl cronTriggerImpl = (CronTriggerImpl) trigger;
String cronExpression = cronTriggerImpl.getCronExpression();
triggerDto.setCron(cronExpression);
// 计算最近10次的触发时间
List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 10);
triggerDto.setRecentFireTimeList(dates);
}
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
triggerDto.setTriggerState(triggerState.toString());
triggerDtoList.add(triggerDto);
}
jobDto.setTriggerDetailDtoList(triggerDtoList);
return jobDto;
}
}