Java 定时任务调度工具 ~ Quartz。
what。
http://www.quartz-scheduler.org/
Quartz 设计模式。
Builder 模式。
Factory 模式。
组件模式。
链式写法。
Quartz 体系结构。
重要组成。
- Trigger。
- TriggerBuilder。
- ThreadPool。
- Schedule。
三个核心概念。
调度器。
任务。
触发器。
Quartz 使用。
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
三要素。
job。(具体业务逻辑)。
Job 接口非常容易实现,只有一个 execute(); 方法,类似 TimeTask 的 run(); 方法,在里面编写业务逻辑。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.quartz;
public interface Job {
void execute(JobExecutionContext var1) throws JobExecutionException;
}
package com.geek.hello.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 打印时间。
// 获取当前时间。并设置为当前时间 3s 后的时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
// 具体业务逻辑。
System.out.println("Hello World");
}
}
Job 实例在 Quartz 中的生命周期。
每次调度器执行 job 时,ta 在调用 execute 方法前会创建一个新的 job 实例。
当调用完成后,关联的 job 对象实例会被释放,释放的实例会被垃圾回收机制回收。
JobDetail。
JobDetail 为 Job 实例提供了许多设置属性,以及 JobDataMap 成员变量属性,ta 用来存储特定 Job 实例的状态信息,调度器需要借助 JobDetail 对象来添加 Job 实例。
重要属性。
-
name。任务名称。
-
group。默认 DEFAULT。
-
jobClass。(HelloJob)实现类。
-
jobDataMap。
package com.geek.hello.quartz;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 重写 org.quartz.Job 中 run(); 方法
// 编写自己的逻辑。
// 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob", "group1")// 标识。
// 自定义参数。
.usingJobData("message", "Hello, myJob1")
.usingJobData("floatJobValue", 3.14F)
.build();
// System.out.println(jobDetail.getKey().getName());// myJob / 6da64b5bd2ee-3e0fb328-7c23-4e56-b4c8-15f00186fec9
// System.out.println(jobDetail.getKey().getGroup());// group1 / DEFAULT
// System.out.println(jobDetail.getKey().getClass());// class org.quartz.JobKey
}
}
schedule。
package com.geek.hello.quartz;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 重写 org.quartz.Job 中 run(); 方法
// 编写自己的逻辑。
// 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob", "group1")// 标识。
// 自定义参数。
.usingJobData("message", "Hello, myJob1")
.usingJobData("floatJobValue", 3.14F)
.build();
// System.out.println(jobDetail.getKey().getName());// myJob / 6da64b5bd2ee-3e0fb328-7c23-4e56-b4c8-15f00186fec9
// System.out.println(jobDetail.getKey().getGroup());// group1 / DEFAULT
// System.out.println(jobDetail.getKey().getClass());// class org.quartz.JobKey
// trigger 对象指定频率。
// 创建 Trigger 实例。定义该 Job 立即执行,并且每隔 2s 重复执行一次,直到永远。
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.usingJobData("message", "Hello, myTrigger1")
.usingJobData("doubleTriggerValue", 2.0D)
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever())// 设置频率。
.build();
// 创建 scheduler 实例。工厂模式。
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time Is: " - simpleDateFormat.format(date));
// 以 trigger 指定的频率执行 JobDetail 任务。
scheduler.scheduleJob(jobDetail, trigger);
}
}
JobExecutionContext。
-
当 Scheduler 调用一个 Job,就会将 JobExecutionContext 传递给 Job 的 execute(); 方法。
-
Job 能通过 JobExecutionContext 对象访问到 Quartz 运行时的环境以及 Job 本身的明细数据。
JobDataMap。
-
在进行任务调度时 JobDataMap 存储在 JobExecutionContext 中,非常方便获取。
-
Job Data Map 可以用来装载任何可序列化的数据对象,
当 job 实例对象被执行时这些参数对象会传递给 ta。 -
JobDataMap 实现了JDK 的 Map 接口,并且添加了一些非常方便的方法用来存取基本数据类型。
获取 JobDataMap。
方法一 ~ 从 Map 中直接获取。
- 传递。
.usingJobData();。
package com.geek.hello.quartz;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 重写 org.quartz.Job 中 run(); 方法
// 编写自己的逻辑。
// 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
// .withIdentity("myJob", "group1")// 标识。
// 自定义参数。
.usingJobData("message", "Hello, myJob1")
.usingJobData("floatJobValue", 3.14F)
.build();
// System.out.println(jobDetail.getKey().getName());// myJob / 6da64b5bd2ee-3e0fb328-7c23-4e56-b4c8-15f00186fec9
// System.out.println(jobDetail.getKey().getGroup());// group1 / DEFAULT
// System.out.println(jobDetail.getKey().getClass());// class org.quartz.JobKey
// trigger 对象指定频率。
// 创建 Trigger 实例。定义该 Job 立即执行,并且每隔 2s 重复执行一次,直到永远。
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.usingJobData("message", "Hello, myTrigger1")
.usingJobData("doubleTriggerValue", 2.0D)
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever())// 设置频率。
.build();
// 创建 Scheduler 实例。工厂模式。
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time Is: " - simpleDateFormat.format(date));
// 以 trigger 指定的频率执行 JobDetail 任务。
scheduler.scheduleJob(jobDetail, trigger);
}
}
- 获取。
package com.geek.hello.quartz;
import org.quartz.*;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
// 具体业务逻辑。
System.out.println("helloWorld,!");
JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
System.out.println("job name: " - jobKey.getName() - ", job group: " - jobKey.getGroup());
// job name: myJob, job group: group1
TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
System.out.println("trigger name: " - triggerKey.getName() - ", trigger group: " - triggerKey.getGroup());
// trigger name: myTrigger, trigger group: group1
// 获取自定义数据。
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();
String jobMsg = jobDataMap.getString("message");
System.out.println("jobMsg = " - jobMsg);
// jobMsg = Hello, myJob1
float jobFloatValue = jobDataMap.getFloat("floatJobValue");
System.out.println("jobFloatValue = " - jobFloatValue);
// jobFloatValue = 3.14
String triggerMsg = triggerDataMap.getString("message");
System.out.println("triggerMsg = " - triggerMsg);
// triggerMsg = Hello, myTrigger1
double triggerDoubleValue = triggerDataMap.getDouble("doubleTriggerValue");
System.out.println("triggerDoubleValue = " - triggerDoubleValue);
// triggerDoubleValue = 2.0
// System.out.println("Hello World");
JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
System.out.println("mergedJobDataMap = " - mergedJobDataMap);
// org.quartz.JobDataMap@93516269
}
}
方法二 ~ Job 实现类中添加 setter 方法对应 JobDataMap 的键值(Quartz 框架默认的 JobFactory 实现类在初始化 job 实例对象时会自动地调用这些 setter 方法)。
package com.geek.hello.quartz;
import lombok.Data;
import org.quartz.*;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
@Data
public class HelloJob implements Job {
private String message;
private Float floatJobValue;
private Double doubleTriggerValue;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
// 具体业务逻辑。
System.out.println("helloWorld,!");
JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
System.out.println("job name: " - jobKey.getName() - ", job group: " - jobKey.getGroup());
// job name: myJob, job group: group1
TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
System.out.println("trigger name: " - triggerKey.getName() - ", trigger group: " - triggerKey.getGroup());
// trigger name: myTrigger, trigger group: group1
// 获取自定义数据。
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();
// String jobMsg = jobDataMap.getString("message");
// System.out.println("jobMsg = " - jobMsg);
// jobMsg = Hello, myJob1
System.out.println("message = " - message);
float jobFloatValue = jobDataMap.getFloat("floatJobValue");
System.out.println("jobFloatValue = " - jobFloatValue);
// jobFloatValue = 3.14
String triggerMsg = triggerDataMap.getString("message");
System.out.println("triggerMsg = " - triggerMsg);
// triggerMsg = Hello, myTrigger1
System.out.println("floatJobValue = " - floatJobValue);
double triggerDoubleValue = triggerDataMap.getDouble("doubleTriggerValue");
System.out.println("triggerDoubleValue = " - triggerDoubleValue);
// triggerDoubleValue = 2.0
System.out.println("doubleTriggerValue = " - doubleTriggerValue);
JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
System.out.println("mergedJobDataMap = " - mergedJobDataMap);
// org.quartz.JobDataMap@93516269
}
}
Trigger。
Quartz 中的触发器。用来告诉调度程序作业什么时候触发。
即 Trigger 对象是用来触发执行 Job 的。
触发器属性。
-
JobKey。
job 实例的标识。触发器被触发时,该指定的 job 实例会执行。 -
StartTime。
首次被触发的时间。
java.util.Date。 -
EndTime。
触发器不再触发的时间。
java.util.Date。
package com.geek.helloTrigger;
import lombok.Data;
import org.quartz.*;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
@Data
public class HelloJob implements Job {
private String message;
private Float floatJobValue;
private Double doubleTriggerValue;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
// 具体业务逻辑。
Trigger trigger = jobExecutionContext.getTrigger();
System.out.println("start time is: " - simpleDateFormat.format(trigger.getStartTime()));
System.out.println("end time is: " - simpleDateFormat.format(trigger.getEndTime()));
JobKey jobKey = trigger.getJobKey();
System.out.println("jobKey = " - jobKey);
System.out.println(jobKey.getName());
System.out.println(jobKey.getGroup());
}
}
package com.geek.helloTrigger;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time Is: " - simpleDateFormat.format(date));
// 重写 org.quartz.Job 中 run(); 方法
// 编写自己的逻辑。
// 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob", "group1")// 标识。
.build();
// 获取距离当前时间 3 秒后的时间。
date.setTime(date.getTime() - 3000);
// 获取距离当前时间 6 秒后的时间。
Date endDate = new Date();
endDate.setTime(date.getTime() - 6000);
// trigger 对象指定频率。
// 创建 Trigger 实例。定义该 Job 立即执行,并且每隔 2s 重复执行一次,直到永远。
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
// .startNow()// 立刻执行。
.startAt(date)// 自定义时间执行。(3 秒之后)。
.endAt(endDate)// 自定义结束时间。(6 秒之后)。
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever())// 设置频率。
.build();
// 创建 Scheduler 实例。工厂模式。
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// 以 trigger 指定的频率执行 JobDetail 任务。
scheduler.scheduleJob(jobDetail, trigger);
}
}
SimpleTrigger。
在一个指定时间段内执行一次作业任务。
或是在指定时间间隔内多次执行作业任务。
package com.geek.trigger.simple;
import lombok.Data;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
@Data
public class HelloJob implements Job {
private String message;
private Float floatJobValue;
private Double doubleTriggerValue;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
// 具体业务逻辑。
System.out.println("hello...");
}
}
package com.geek.trigger.simple;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time Is: " - simpleDateFormat.format(date));
// 重写 org.quartz.Job 中 run(); 方法
// 编写自己的逻辑。
// 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob", "group1")// 标识。
.build();
// 获取距离当前时间 4 秒后的时间。
date.setTime(date.getTime() - 4000);
// trigger 对象指定频率。
// 距离当前时间 4 秒后执行且只执行一次。
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(date)
.build();
// 创建 Scheduler 实例。工厂模式。
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// 以 trigger 指定的频率执行 JobDetail 任务。
scheduler.scheduleJob(jobDetail, trigger);
}
}
package com.geek.trigger.simple;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
public class HelloScheduler02 {
public static void main(String[] args) throws SchedulerException {
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time Is: " - simpleDateFormat.format(date));
// 重写 org.quartz.Job 中 run(); 方法
// 编写自己的逻辑。
// 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob", "group1")// 标识。
.build();
// 获取距离当前时间 4 秒后的时间。
date.setTime(date.getTime() - 4000);
// trigger 对象指定频率。
// 距离当前时间 4 秒后第一次执行任务,之后每隔 2 秒重复执行一次。
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(date)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)// 每隔 2 秒。
// .withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY))// 重复无限次。
.withRepeatCount(3))// 重复 3 次。
.build();
// 创建 Scheduler 实例。工厂模式。
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// 以 trigger 指定的频率执行 JobDetail 任务。
scheduler.scheduleJob(jobDetail, trigger);
}
}
package com.geek.trigger.simple;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
public class HelloScheduler02 {
public static void main(String[] args) throws SchedulerException {
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time Is: " - simpleDateFormat.format(date));
// 重写 org.quartz.Job 中 run(); 方法
// 编写自己的逻辑。
// 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob", "group1")// 标识。
.build();
// 获取距离当前时间 4 秒后的时间。
date.setTime(date.getTime() - 4000);
// 获取距离当前时间 6 秒后的时间。
Date endDate = new Date();
endDate.setTime(date.getTime() - 6000);
// trigger 对象指定频率。
// 距离当前时间 4 秒后第一次执行任务,之后每隔 2 秒重复执行一次。
// 直到 6 秒停止。
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(date)
.endAt(endDate)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)// 每隔 2 秒。
.withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY))// 重复无限次。
// .withRepeatCount(3))// 重复 3 次。
.build();
// 创建 Scheduler 实例。工厂模式。
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// 以 trigger 指定的频率执行 JobDetail 任务。
scheduler.scheduleJob(jobDetail, trigger);
}
}
CronTrigger。
基于日历的作业调度器。
不是像 SimpleTrigger 那样精确指定时间 间隔。
比 SimpleTrigger 更常用。
Cron 表达式。
https://www.bejson.com/othertools/cron/
计划任务,是任务在约定的时间执行已经计划好的工作,这是表面的意思。在Linux中,我们经常用到 cron 服务器来完成这项工作。cron服务器可以根据配置文件约定的时间来执行特定的任务。
用于配置 CronTrigger 实例。
由 7 个子表达式组成的字符串,描述了时间表的详细信息。
[秒] [分] [时] [日] [月] [周] [年]
Seconds Minutes Hours DayofMonth Month DayofWeek Year或
Seconds Minutes Hours DayofMonth Month DayofWeek
,
~ 或。
-
~ 范围。
*
~ 每。
/
~ 每隔多久。
?
~ 不关心,随便。eg. 星期位 ?表示不管星期几。
表达式 | 含义 |
---|---|
0 15 10 ? * * | 每天 10 点 15。 |
0 0/5 14 * * ? | 每天 14 点到 14 点 59 (整点开始,每隔 5 分钟)。 |
0 15 10 ? * MON-FRI | 周一到周五每天 10 点 15。 |
0 15 10 ? * 6#3 | 每月第三周的星期五的 10 点 15。 |
0 15 10 ? * 6L 2016-2017 | 2016 到 2017 年每月最后一周的星期五的 10 点 15。 |
L
~ 最后。
W
~ 向后最近的工作日(周一 ~ 周五)。
#
~ 序号。表示每月的第一个周几。周字段 ~ 6#3 ~ 每月第三个周六。
package com.geek.scheduler;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time Is: " - simpleDateFormat.format(date));
// 重写 org.quartz.Job 中 run(); 方法
// 编写自己的逻辑。
// 创建一个 JobDetail 实例,将该实例与 HelloJob 绑定。
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob", "group1")// 标识。
.build();
// trigger 对象指定频率。
CronTrigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("* * * * * ? *")// 每秒。
// CronScheduleBuilder.cronSchedule("0 58 15 ? * * 2020")
// 2020 年每天 10 点 13。
// 0 13 10 ? * * 2020
// 每天 14 点到 14 点 59 分 55 秒,以及 18 点整到 18 点 59 分 55 秒,每 5 秒触发一次。
// 0/5 * 14,18 * * ?
// 每月周一至周五的 10 点 13 分。
// * 13 10 * 0-4 ?
// 每月最后一天的 10 点 13。
// 每月第三个周五的 10 点 13 分。
)
.build();
// 创建 scheduler 实例。工厂模式。
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 启动。
scheduler.start();
// // StdSchedulerFactory。
// // 使用一组参数(java.util.Properties)来创建和初始化 Quartz 调度器。
// // 配置参数一般存储在 quartz.properties 中。
// // 调用 stdSchedulerFactory.getScheduler(); 就能创建和初始化调度器对象。
// StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
// Scheduler scheduler = stdSchedulerFactory.getScheduler();
// 以 trigger 指定的频率执行 JobDetail 任务。
// 返回 Date。
Date job = scheduler.scheduleJob(jobDetail, trigger);
System.out.println(simpleDateFormat.format(job));
// schedule 执行 2 秒后挂起。
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.standby();
// scheduler.shutdown();// 不能重启了。
// scheduler.shutdown(true);// waitForJobsToComplete。
scheduler.shutdown(false);// waitForJobsToComplete。
System.out.println(scheduler.isShutdown());
// 挂起 3 秒后再次启动。
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.start();
}
}
package com.geek.scheduler;
import lombok.Data;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
@Data
public class HelloJob implements Job {
private String message;
private Float floatJobValue;
private Double doubleTriggerValue;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 打印当前时间。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Exec Time Is: " - simpleDateFormat.format(date));
// 具体业务逻辑。
System.out.println("hello...");
}
}
- quartz.properties。
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# ~ ~ ~ 调度器配置。~ ~ ~
#
#org.quartz.scheduler.instanceId 属性和前者一样,也允许任何字符串,但这个值必须是在所有调度器实例中是唯一的,尤其是在一个集群当中,作为集群的唯一 key。假如你想 Quartz 帮你生成这个值的话,可以设置为AUTO 。
# org.quartz.scheduler.instanceName 属性用来区分特定的调度器实例,可以按照功能用途来给调度器起名。
org.quartz.scheduler.instanceName:DefaultQuartzScheduler
org.quartz.scheduler.rmi.export:false
org.quartz.scheduler.rmi.proxy:false
org.quartz.scheduler.wrapJobExecutionInUserTransaction:false
# ~ ~ ~ 线程池配置。~ ~ ~
#
# 线程池的实现类。
org.quartz.threadPool.class:org.quartz.simpl.SimpleThreadPool
# 线程数,至少为 1(无默认值)(一般设置为 1 ~ 100 之间的整数)。
org.quartz.threadPool.threadCount:10
# 线程池优先级。
# public
#class Thread implements Runnable {
# /**
# * The minimum priority that a thread can have.
# */
# public final static int MIN_PRIORITY = 1;
#
# /**
# * The default priority that is assigned to a thread.
# */
# public final static int NORM_PRIORITY = 5;
#
# /**
# * The maximum priority that a thread can have.
# */
# public final static int MAX_PRIORITY = 10;
org.quartz.threadPool.threadPriority:5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread:true
#
# 作业存储配置。描述了在调度器实例的生命周期中,Job 和 Trigger 信息是如何被存储的。
org.quartz.jobStore.misfireThreshold:60000
#
# 插件配置。满足特定需求用到的 Quartz 插件的配置。
org.quartz.jobStore.class:org.quartz.simpl.RAMJobStore
Spring。
方式 1 ~ MethodInvokingJobDetailFactoryBean。
package com.geek.springquartz.quartz;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
@Component("myBean")
public class MyBean {
public void printMessage() {
// 打印当前的执行时间,格式为 2020-01-01 00:00:00。
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("MyBean Executes!" - simpleDateFormat.format(date));
}
}
<!-- quartz 方式 1。-->
<bean id="simpleJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myBean"/>
<property name="targetMethod" value="printMessage"/>
</bean>
方式 2 ~ JobDetailFactoryBean。
<!-- quartz 方式 2。可以给作业传递数据,更加灵活。-->
<bean id="jobDetailFactoryBean"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 继承自 QuartzJobBean 的类。重写 executeInternal(); 方法。-->
<property name="jobClass"
value="com.geek.springquartz.quartz.FirstScheduledJob"/>
<!-- 可选,传入自定义数据。
自定义一个类 com.geek.springquartz.quartz.FirstScheduledJob 继承 QuartzJobBean。
@Autowired private AnotherBean anotherBean;
自定义逻辑写在 protected void executeInternal(JobExecutionContext arg0)
throws JobExecutionException { 中。
-->
<property name="jobDataMap">
<map>
<entry key="anotherBean" value-ref="anotherBean"/>
</map>
</property>
<property name="Durability" value="true"/>
</bean>
package com.geek.springquartz.quartz;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author geek
*/
public class FirstScheduledJob extends QuartzJobBean {
@Autowired
private AnotherBean anotherBean;
public void setAnotherBean(AnotherBean anotherBean) {
this.anotherBean = anotherBean;
}
@Override
protected void executeInternal(JobExecutionContext arg0)
throws JobExecutionException {
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("FirstScheduledJob Executes!" - simpleDateFormat.format(date));
this.anotherBean.printAnotherMessage();
}
}
package com.geek.springquartz.quartz;
import org.springframework.stereotype.Component;
/**
* @author geek
*/
@Component("anotherBean")
public class AnotherBean {
public void printAnotherMessage() {
System.out.println("AnotherMessage");
}
}
Trigger。
<!-- Trigger。-->
<!-- trigger 1。-->
<!-- 距离当前时间 1 秒之后执行,之后每隔两秒钟执行一次。-->
<bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleJobDetail"/>
<property name="startDelay" value="1000"/>
<property name="repeatInterval" value="2000"/>
</bean>
<!-- trigger 2。-->
<!-- 每隔 5 秒钟执行一次。-->
<bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="firstComplexJobDetail"/>
<property name="cronExpression" value="0/5 * * ? * *"/>
</bean>
Scheduler。
<!-- scheduler。-->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="simpleJobDetail"/>
<ref bean="firstComplexJobDetail"/>
</list>
</property>
<property name="triggers">
<list>
<ref bean="mySimpleTrigger"/>
<ref bean="myCronTrigger"/>
</list>
</property>
</bean>
MyBean Executes!2020-09-05 18:22:10
MyBean Executes!2020-09-05 18:22:12
MyBean Executes!2020-09-05 18:22:14
FirstScheduledJob Executes!2020-09-05 18:22:15
AnotherMessage
MyBean Executes!2020-09-05 18:22:16
MyBean Executes!2020-09-05 18:22:18
FirstScheduledJob Executes!2020-09-05 18:22:20
AnotherMessage
MyBean Executes!2020-09-05 18:22:20
MyBean Executes!2020-09-05 18:22:22
MyBean Executes!2020-09-05 18:22:24
FirstScheduledJob Executes!2020-09-05 18:22:25
AnotherMessage
MyBean Executes!2020-09-05 18:22:26
MyBean Executes!2020-09-05 18:22:28
FirstScheduledJob Executes!2020-09-05 18:22:30
AnotherMessage