在遇到如下几种场景可以考虑使用任务调度来解决:
在线 Cron 表达式生成器
Seconds | Minutes | Hours | DayOfMonth | Month | DayOfWeek | Year | |
---|---|---|---|---|---|---|---|
有效范围 | 0-59 | 0-59 | 0-23 | 1-31 | 1-12 | 1-7 | 1970-2099 |
是否支持"," | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
是否支持"-" | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
是否支持"*" | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
是否支持"/" | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
是否支持"L" | 支持 | 支持 | |||||
是否支持"W" | 支持 | ||||||
是否支持"C" | 支持 | 支持 | |||||
是否支持"?" | 支持 | 支持 | |||||
是否支持"#" | 支持 |
Cron 表达式是一个字符串,分为 6 或者 7 个域,有两种语法格式:
Seconds Minutes Hours DayOfMonth Month DayOfWeek Year
Seconds Minutes Hours DayOfMonth Month DayOfWeek
Month 域的范围也可以为 JAN-DEC。
DayOfWeek 域的范围也可以为 SUN-SAT,1 表示星期日,2 表示星期一。
,
表示枚举值。比如 Minutes 域使用 5,20,表示在第 5 分钟和第 20 分钟分别触发一次。
-
表示范围。比如 Minutes 域使用 5-20,表示从第 5 分钟到 20 分钟每分钟触发一次。
*
表示任意值。比如 Minutes 域使用 *
,表示每分钟触发一次。
/
表示数值的增量。比如 Minutes 域使用 0/5,表示从第 0 分钟开始,每隔 5 分钟触发一次。
L
表示最后。比如 DayOfWeek 域使用 5L
,表示在最后一个周四触发。DayOfMonth 域使用 L
,表示在每月的最后一日触发。
W
表示有效工作日(周一到周五)。比如 DayOfMonth 域使用 5W
,如果 5 日是星期六,则将在星期五触发;如果 5 日是星期天,则将在星期一触发;如果 5 日是星期一到星期五的某一天,则就在 5 日触发。也就是说离指定日期最近的有效工作日触发,但是不会跨过月份。
LW
表示某个月的最后一个工作日。
?
表示任意值。如果 DayOfMonth 域或者 DayOfWeek 域中任意一个指定了具体值或者 *
,则另一个使用 ?
。
#
表示某个月的第几个星期几。比如 DayOfWeek 域使用 4#2
,表示某个月的第二个星期三触发。
// 每月1日的凌晨2点调度任务
0 0 2 1 * ?
// 周一到周五每天上午10:15调度任务
0 15 10 ? * MON-FRI
// 2002-2006年的每个月的最后一个星期五上午10:15调度任务
0 15 10 ? * 6L 2002-2006
// 每天上午10点,下午2点,4点调度任务
0 0 10,14,16 * * ?
// 朝九晚五工作时间内每半小时
0 0/15 9-17 * * ?
// 每天下午2点到下午2:59期间的每1分钟
0 * 14 * * ?
// 每天下午2点到下午2:55期间的每5分钟
0 0/5 14 * * ?
// 每天下午2点到2:55期间和下午6点到6:55期间的每5分钟
0 0/5 14,18 * * ?
// 每年三月的星期三的下午2:10和2:44触发
0 10,44 14 ? 3 WED
// 每月15日上午10:15
0 15 10 15 * ?
// 每月最后一日的上午10:15
0 15 10 L * ?
// 每月的第三个星期五上午10:15
0 15 10 ? * 6#3
定义要执行的任务,代码方式/脚本方式。
配置任务触发的规则。
多个任务可以并发执行,互不干扰。
需要一个调度器的角色,控制任务启动、停止等。
可以集成 Spring、Spring Boot。
Quartz 是一个特性丰富的、开源的任务调度库,几乎可以嵌入所有的 Java 程序,包括很小的独立应用程序到大型商业系统。Quartz 可以用来创建成百上千的简单的或者复杂的任务,并且这些任务可以作为执行任何事情的标准 Java 组件。Quartz 拥有很多企业级别的特性,包括支持 JTA 事务和集群。
Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java components that may execute virtually anything you may program them to do. The Quartz Scheduler includes many enterprise-class features, such as support for JTA transactions and clustering.
可以实现 Job 接口来定义一个任务,然后重写它的 execute 方法来定义任务执行的逻辑。
public class MyJob implements Job {
private static final Logger LOGGER = LoggerFactory.getLogger(MyJob.class);
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
LOGGER.info(simpleDateFormat.format(new Date()) + ", 任务1执行了, " + jobDataMap.getString("hello"));
}
}
而调度器的调度方法需要指定一个 JobDetail,即任务明细。JobDetail 可以通过 JobBuilder 的相关方法进行实例化。
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "my-job-group")
.usingJobData("hello", "tom")
.usingJobData("hi", "selina")
.build();
Quartz 中提供了三个跟任务相关的注解:
@DisallowConcurrentExecution(禁止多个实例并发执行标注该注解的任务)
@PersistJobDataAfterExecution(任务执行完成后重新持久化任务相关的JobDataMap)
@ExecuteInJTATransaction(将任务的执行封装到一个JTA事务中)
接下来,看下 JobBuilder 中定义的一些比较重要的方法。
1、newJob 方法
实例化 JobBuilder(可以指定一个任务)
public static JobBuilder newJob() {
return new JobBuilder();
}
public static JobBuilder newJob(Class<? extends Job> jobClass) {
JobBuilder b = new JobBuilder();
b.ofType(jobClass);
return b;
}
2、ofType 方法
指定任务
public JobBuilder ofType(Class<? extends Job> jobClazz) {
this.jobClass = jobClazz;
return this;
}
3、withIdentity 方法
指定任务的名字和组
public JobBuilder withIdentity(String name) {
key = new JobKey(name, null);
return this;
}
public JobBuilder withIdentity(String name, String group) {
key = new JobKey(name, group);
return this;
}
public JobBuilder withIdentity(JobKey jobKey) {
this.key = jobKey;
return this;
}
4、withDescription 方法
指定任务的描述
public JobBuilder withDescription(String description) {
this.description = description;
return this;
}
5、requestRecovery 方法
指定任务遇到“recovery”或者“fail-over”情形是否应该重新执行(默认 true,即重新执行)
public JobBuilder requestRecovery() {
this.shouldRecover = true;
return this;
}
public JobBuilder requestRecovery(boolean jobShouldRecover) {
this.shouldRecover = jobShouldRecover;
return this;
}
6、storeDurably 方法
指定任务是否应该持久化(默认 true,即持久化)
public JobBuilder storeDurably() {
this.durability = true;
return this;
}
public JobBuilder storeDurably(boolean jobDurability) {
this.durability = jobDurability;
return this;
}
7、usingJobData 方法
添加一组键值对到 JobDetail 的 JobDataMap 属性中
public JobBuilder usingJobData(String dataKey, String value) {
jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Integer value) {
jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Long value) {
jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Float value) {
jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Double value) {
jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Boolean value) {
jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(JobDataMap newJobDataMap) {
jobDataMap.putAll(newJobDataMap);
return this;
}
8、setJobData 方法
覆盖 JobDetail 的 JobDataMap 属性
public JobBuilder setJobData(JobDataMap newJobDataMap) {
jobDataMap = newJobDataMap;
return this;
}
9、build 方法
构建 JobDetailImpl 实例
public JobDetail build() {
JobDetailImpl job = new JobDetailImpl();
job.setJobClass(jobClass);
job.setDescription(description);
if(key == null)
key = new JobKey(Key.createUniqueName(null), null);
job.setKey(key);
job.setDurability(durability);
job.setRequestsRecovery(shouldRecover);
if(!jobDataMap.isEmpty())
job.setJobDataMap(jobDataMap);
return job;
}
任务触发的规则。
调度器的调度方法需要指定一个 Trigger 实例,即触发器。可以通过 TriggerBuilder 的相关方法构建一个 Trigger 实例。
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "my-trigger-group")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
接下来看下 TriggerBuilder 定义的一些比较重要的方法。
1、newTrigger 方法
构建 TriggerBuilder 实例
public static TriggerBuilder<Trigger> newTrigger() {
return new TriggerBuilder<Trigger>();
}
2、withIdentity 方法
设置触发器的名字和组名
public TriggerBuilder<T> withIdentity(String name) {
key = new TriggerKey(name, null);
return this;
}
public TriggerBuilder<T> withIdentity(String name, String group) {
key = new TriggerKey(name, group);
return this;
}
public TriggerBuilder<T> withIdentity(TriggerKey triggerKey) {
this.key = triggerKey;
return this;
}
3、withDescription 方法
设置触发器的描述
public TriggerBuilder<T> withDescription(String triggerDescription) {
this.description = triggerDescription;
return this;
}
4、withPriority 方法
设置触发器的优先级(如果有多个启动时间相同的触发器,根据触发器的优先级由大到小的顺序进行启动)
public TriggerBuilder<T> withPriority(int triggerPriority) {
this.priority = triggerPriority;
return this;
}
5、modifiedByCalendar 方法
设置应用到该触发器调度的 Calendar 的名字
public TriggerBuilder<T> modifiedByCalendar(String calName) {
this.calendarName = calName;
return this;
}
6、startAt 方法
设置触发器的开始时间
public TriggerBuilder<T> startAt(Date triggerStartTime) {
this.startTime = triggerStartTime;
return this;
}
7、startNow 方法
设置触发器立即开始
public TriggerBuilder<T> startNow() {
this.startTime = new Date();
return this;
}
8、endAt 方法
设置触发器的结束时间
public TriggerBuilder<T> endAt(Date triggerEndTime) {
this.endTime = triggerEndTime;
return this;
}
9、withSchedule 方法
设置用于触发器调度的规则,即 ScheduleBuilder
public <SBT extends T> TriggerBuilder<SBT> withSchedule(ScheduleBuilder<SBT> scheduleBuilder) {
this.scheduleBuilder = scheduleBuilder;
return (TriggerBuilder<SBT>) this;
}
10、forJob 方法
设置触发器关联的任务
public TriggerBuilder<T> forJob(JobKey jobKey) {
this.jobKey = jobKey;
return this;
}
public TriggerBuilder<T> forJob(String jobName) {
this.jobKey = new JobKey(jobName, null);
retun this;
}
public TriggerBuilder<T> forJob(String jobName, String jobGroup) {
this.jobKey = new JobKey(jobName, jobGroup);
return this;
}
public TriggerBuilder<T> forJob(JobDetail jobDetail) {
JobKey k = jobDetail.getKey();
if (k.getName() == null) {
throw new IllegalArgumentException("The given job has not yet had a name assigned to it.");
}
this.jobKey = k;
return this;
}
11、usingJobData 方法
添加一组键值对到触发器的 JobDataMap 属性中
public TriggerBuilder<T> usingJobData(String dataKey, String value) {
jobDataMap.put(dataKey, value);
return this;
}
public TriggerBuilder<T> usingJobData(String dataKey, String value) {
jobDataMap.put(dataKey, value);
return this;
}
public TriggerBuilder<T> usingJobData(String dataKey, Integer value) {
jobDataMap.put(dataKey, value);
return this;
}
public TriggerBuilder<T> usingJobData(String dataKey, Long value) {
jobDataMap.put(dataKey, value);
return this;
}
public TriggerBuilder<T> usingJobData(String dataKey, Float value) {
jobDataMap.put(dataKey, value);
return this;
}
public TriggerBuilder<T> usingJobData(String dataKey, Double value) {
jobDataMap.put(dataKey, value);
return this;
}
public TriggerBuilder<T> usingJobData(String dataKey, Boolean value) {
jobDataMap.put(dataKey, value);
return this;
}
public TriggerBuilder<T> usingJobData(JobDataMap newJobDataMap) {
for(String dataKey: jobDataMap.keySet()) {
newJobDataMap.put(dataKey, jobDataMap.get(dataKey));
}
jobDataMap = newJobDataMap;
return this;
}
12、build 方法
构建具体的 Trigger 实例
public T build() {
if(scheduleBuilder == null)
scheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
MutableTrigger trig = scheduleBuilder.build();
trig.setCalendarName(calendarName);
trig.setDescription(description);
trig.setStartTime(startTime);
trig.setEndTime(endTime);
if(key == null)
key = new TriggerKey(Key.createUniqueName(null), null);
trig.setKey(key);
if(jobKey != null)
trig.setJobKey(jobKey);
trig.setPriority(priority);
if(!jobDataMap.isEmpty())
trig.setJobDataMap(jobDataMap);
return (T) trig;
}
指定时间间隔(时分秒)重复执行 n 次任务
1、simpleSchedule 方法
构建 SimpleScheduleBuilder 实例
public static SimpleScheduleBuilder simpleSchedule();
2、repeat…Forever 方法
指定时间间隔(时分秒)永久重复执行
// 指定每隔一分钟永久重复执行
public static SimpleScheduleBuilder repeatMinutelyForever();
// 指定每隔多少分钟永久重复执行
public static SimpleScheduleBuilder repeatMinutelyForever(int minutes);
// 指定每隔一秒永久重复执行
public static SimpleScheduleBuilder repeatSecondlyForever();
// 指定每隔多少秒永久重复执行
public static SimpleScheduleBuilder repeatSecondlyForever(int seconds);
// 指定每隔一小时永久重复执行
public static SimpleScheduleBuilder repeatHourlyForever();
// 指定每隔多少小时永久重复执行
public static SimpleScheduleBuilder repeatHourlyForever(int hours);
3、repeat…ForTotalCount 方法
指定时间间隔(时分秒)重复执行 n 次任务
// 每隔一分钟重复执行一次,重复执行(count - 1)次
public static SimpleScheduleBuilder repeatMinutelyForTotalCount(int count);
// 每隔多少分钟重复执行一次,重复执行(count - 1)次
public static SimpleScheduleBuilder repeatMinutelyForTotalCount(int count, int minutes);
// 每隔一秒重复执行一次,重复执行(count - 1)次
public static SimpleScheduleBuilder repeatSecondlyForTotalCount(int count);
// 每隔多少秒重复执行一次,重复执行(count - 1)次
public static SimpleScheduleBuilder repeatSecondlyForTotalCount(int count, int seconds);
// 每隔一小时重复执行一次,重复执行(count - 1)次
public static SimpleScheduleBuilder repeatHourlyForTotalCount(int count);
// 每隔多少小时重复执行一次,重复执行(count - 1)次
public static SimpleScheduleBuilder repeatHourlyForTotalCount(int count, int hours);
4、withInterval… 方法
指定时间间隔(时分秒毫秒)执行一次
// 每隔多少毫秒执行一次
public SimpleScheduleBuilder withIntervalInMilliseconds(long intervalInMillis);
// 每隔多少秒执行一次
public SimpleScheduleBuilder withIntervalInSeconds(int intervalInSeconds);
// 每隔多少分钟执行一次
public SimpleScheduleBuilder withIntervalInMinutes(int intervalInMinutes);
// 每隔多少小时执行一次
public SimpleScheduleBuilder withIntervalInHours(int intervalInHours);
5、withRepeatCount 方法
指定重复执行的次数
public SimpleScheduleBuilder withRepeatCount(int triggerRepeatCount);
6、repeatForever 方法
指定永久重复执行
public SimpleScheduleBuilder repeatForever();
7、withMisfire 方法
设置触发器错过启动时间的补偿策略
public SimpleScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires();
public SimpleScheduleBuilder withMisfireHandlingInstructionFireNow();
public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithExistingCount();
public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithRemainingCount();
public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithExistingCount();
public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithRemainingCount();
每隔多少时间间隔执行一次
1、calendarIntervalSchedule 方法
构建 CalendarIntervalScheduleBuilder 实例
public static CalendarIntervalScheduleBuilder calendarIntervalSchedule();
2、withInterval…方法
每隔多少时间间隔执行一次
// 每隔多少时间间隔执行一次
public CalendarIntervalScheduleBuilder withInterval(int timeInterval, IntervalUnit unit);
// 每隔多少秒执行一次
public CalendarIntervalScheduleBuilder withIntervalInSeconds(int intervalInSeconds);
// 每隔多少分钟执行一次
public CalendarIntervalScheduleBuilder withIntervalInMinutes(int intervalInMinutes);
// 每隔多少小时执行一次
public CalendarIntervalScheduleBuilder withIntervalInHours(int intervalInHours);
// 每隔多少天执行一次
public CalendarIntervalScheduleBuilder withIntervalInDays(int intervalInDays);
// 每隔多少周执行一次
public CalendarIntervalScheduleBuilder withIntervalInWeeks(int intervalInWeeks);
// 每隔多少月执行一次
public CalendarIntervalScheduleBuilder withIntervalInMonths(int intervalInMonths);
// 每隔多少年执行一次
public CalendarIntervalScheduleBuilder withIntervalInYears(int intervalInYears);
3、withMisfire… 方法
设置触发器错过启动时间的补偿策略
public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires();
public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionDoNothing();
public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionFireAndProceed();
4、inTimeZone 方法
设置时区
public CalendarIntervalScheduleBuilder inTimeZone(TimeZone timezone);
5、build 方法
构建 CalendarIntervalTriggerImpl 实例
public MutableTrigger build();
指定时刻或者时间间隔重复执行 n 次
1、dailyTimeIntervalSchedule 方法
构建 DailyTimeIntervalScheduleBuilder 实例
public static DailyTimeIntervalScheduleBuilder dailyTimeIntervalSchedule();
2、withInterval… 方法
每隔多少时间间隔执行一次
// 每隔多少时间间隔执行一次
public DailyTimeIntervalScheduleBuilder withInterval(int timeInterval, IntervalUnit unit);
// 每隔多少秒执行一次
public DailyTimeIntervalScheduleBuilder withIntervalInSeconds(int intervalInSeconds);
// 每隔多少分钟执行一次
public DailyTimeIntervalScheduleBuilder withIntervalInMinutes(int intervalInMinutes);
// 每隔多少小时执行一次
public DailyTimeIntervalScheduleBuilder withIntervalInHours(int intervalInHours);
3、onDaysOf… 方法
指定一周的哪几天执行
// 指定一周的哪几天执行
public DailyTimeIntervalScheduleBuilder onDaysOfTheWeek(Set<Integer> onDaysOfWeek);
// 指定一周的哪几天执行
public DailyTimeIntervalScheduleBuilder onDaysOfTheWeek(Integer ... onDaysOfWeek);
// 指定一周的星期一到星期五执行
public DailyTimeIntervalScheduleBuilder onMondayThroughFriday();
// 指定一周的星期六、星期日执行
public DailyTimeIntervalScheduleBuilder onSaturdayAndSunday();
// 指定每天执行
public DailyTimeIntervalScheduleBuilder onEveryDay();
4、startingDailyAt 方法
从某个时刻开始执行
public DailyTimeIntervalScheduleBuilder startingDailyAt(TimeOfDay timeOfDay);
5、endingDailyAt 方法
从某个时刻结束执行
public DailyTimeIntervalScheduleBuilder endingDailyAt(TimeOfDay timeOfDay);
6、withRepeatCount 方法
重复执行 (repeatCount - 1) 次
public DailyTimeIntervalScheduleBuilder withRepeatCount(int repeatCount);
7、withMisfire 方法
触发器错过启动的补偿策略
public DailyTimeIntervalScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires();
public DailyTimeIntervalScheduleBuilder withMisfireHandlingInstructionDoNothing();
public DailyTimeIntervalScheduleBuilder withMisfireHandlingInstructionFireAndProceed();
8、build 方法
构建 DailyTimeIntervalTriggerImpl 实例
public MutableTrigger build()
指定 cron 表达式
1、cronSchedule 方法
指定 cron 表达式
public static CronScheduleBuilder cronSchedule(String cronExpression)
2、build 方法
构建 CronTriggerImpl 实例
public MutableTrigger build()
可以用来指定触发器的启动时间以及排除启动时间。
包括 AnnualCalendar、BaseCalendar、CronCalendar、DailyCalendar、HolidayCalendar、MonthlyCalendar、WeeklyCalendar。
AnnualCalendar annualCalendar = new AnnualCalendar();
// 排除 2023-02-28(注意月份从 0 开始)
annualCalendar.setDayExcluded(new GregorianCalendar(2023, 1, 28), true);
// 添加日历
scheduler.addCalendar("myCalendar", annualCalendar, false, false);
通过 SchedulerFactory 获取调度器实例。
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
控制调度器
// 启动调度器
void start() throws SchedulerException;
// 延迟启动调度器
void startDelayed(int seconds) throws SchedulerException;
// 挂起调度器
void standby() throws SchedulerException;
// 关闭调度器
void shutdown() throws SchedulerException;
// 优雅关闭调度器
void shutdown(boolean waitForJobsToComplete) throws SchedulerException;
调度/取消调度任务
// 调度任务
Date scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException;
Date scheduleJob(Trigger trigger) throws SchedulerException;
void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException;
void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) throws SchedulerException;
// 取消调度任务
boolean unscheduleJob(TriggerKey triggerKey) throws SchedulerException;
boolean unscheduleJobs(List<TriggerKey> triggerKeys) throws SchedulerException;
// 重新调度任务
Date rescheduleJob(TriggerKey triggerKey, Trigger newTrigger) throws SchedulerException;
添加、删除与执行任务
// 添加任务
void addJob(JobDetail jobDetail, boolean replace) throws SchedulerException;
void addJob(JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException;
// 删除任务
boolean deleteJob(JobKey jobKey) throws SchedulerException;
boolean deleteJobs(List<JobKey> jobKeys) throws SchedulerException;
// 执行任务
void triggerJob(JobKey jobKey) throws SchedulerException;
void triggerJob(JobKey jobKey, JobDataMap data) throws SchedulerException;
暂停与恢复执行任务
// 暂停执行任务
void pauseJob(JobKey jobKey) throws SchedulerException;
void pauseJobs(GroupMatcher<JobKey> matcher) throws SchedulerException;
void pauseTrigger(TriggerKey triggerKey) throws SchedulerException;
void pauseTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException;
void pauseAll() throws SchedulerException;
// 恢复执行任务
void resumeJob(JobKey jobKey) throws SchedulerException;
void resumeJobs(GroupMatcher<JobKey> matcher) throws SchedulerException;
void resumeTrigger(TriggerKey triggerKey) throws SchedulerException;
void resumeTriggers(GroupMatcher<TriggerKey> matcher) throws SchedulerException;
void resumeAll() throws SchedulerException;
添加与删除日历
// 添加日历
void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException;
// 删除日历
boolean deleteCalendar(String calName) throws SchedulerException;
删除所有任务、触发器、日历
void clear() throws SchedulerException;
通过实现 JobListener 接口来定义一个任务监听器。然后获取 Scheduler 的 ListenerManager 属性,调用 addJobListener 方法来添加一个任务监听器。
自定义任务监听器
public class MyJobListener implements JobListener {
private static final Logger LOGGER = LoggerFactory.getLogger(MyJobListener.class);
@Override
public String getName() {
return "myJobListener";
}
/**
* 任务在执行之前
*/
@Override
public void jobToBeExecuted(JobExecutionContext context) {
LOGGER.info("job to be executed");
}
/**
* 任务在执行之前,被触发器监听器终止了任务的执行
*/
@Override
public void jobExecutionVetoed(JobExecutionContext context) {
LOGGER.info("job execution vetoed");
}
/**
* 任务在执行完成之后
*/
@Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
LOGGER.info("job was executed");
}
}
添加任务监听器
public void addJobListener(JobListener jobListener);
public void addJobListener(JobListener jobListener, Matcher<JobKey> matcher);
public void addJobListener(JobListener jobListener, Matcher<JobKey>... matchers);
public void addJobListener(JobListener jobListener, List<Matcher<JobKey>> matchers);
通过实现 TriggerListener 接口来自定义触发器监听器。然后获取 Scheduler 的 ListenerManager 属性,调用 addTriggerListener 方法来添加一个触发器监听器。
自定义触发器监听器
public class MyTriggerListener implements TriggerListener {
private static final Logger LOGGER = LoggerFactory.getLogger(MyTriggerListener.class);
@Override
public String getName() {
return "myTriggerListener";
}
/**
* 触发器启动并且在执行任务之前
*/
@Override
public void triggerFired(Trigger trigger, JobExecutionContext context) {
LOGGER.info("trigger fired");
}
/**
* 在triggerFired方法执行之后,方法返回值决定是否终止任务的执行
*/
@Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
LOGGER.info("veto job execution : " + false);
return false;
}
/**
* 触发器错过启动的时间
*/
@Override
public void triggerMisfired(Trigger trigger) {
LOGGER.info("trigger misfired");
}
/**
* 触发器启动并且任务执行完成之后
*/
@Override
public void triggerComplete(Trigger trigger, JobExecutionContext context, Trigger.CompletedExecutionInstruction triggerInstructionCode) {
LOGGER.info("trigger complete");
}
}
添加触发器监听器
public void addTriggerListener(TriggerListener triggerListener);
public void addTriggerListener(TriggerListener triggerListener, Matcher<TriggerKey> matcher);
public void addTriggerListener(TriggerListener triggerListener, Matcher<TriggerKey> ... matchers);
public void addTriggerListener(TriggerListener triggerListener, List<Matcher<TriggerKey>> matchers);
通过实现 SchedulerListener 接口来定义一个调度器监听器。然后获取 Scheduler 的 ListenerManager 属性,调用 addSchedulerListener 方法来添加一个调度器监听器。
自定义调度器监听器
public class MySchedulerListener implements SchedulerListener {
private static final Logger LOGGER = LoggerFactory.getLogger(MySchedulerListener.class);
/**
* 任务执行
*/
@Override
public void jobScheduled(Trigger trigger) {
LOGGER.info("jobScheduled");
}
/**
* 任务取消执行
*/
@Override
public void jobUnscheduled(TriggerKey triggerKey) {
LOGGER.info("jobUnscheduled");
}
/**
* 触发器最后一次执行
*/
@Override
public void triggerFinalized(Trigger trigger) {
LOGGER.info("triggerFinalized");
}
/**
* 触发器暂停执行
*/
@Override
public void triggerPaused(TriggerKey triggerKey) {
LOGGER.info("triggerPaused");
}
/**
* 一组触发器暂停执行
*/
@Override
public void triggersPaused(String triggerGroup) {
LOGGER.info("triggersPaused");
}
/**
* 触发器恢复执行
*/
@Override
public void triggerResumed(TriggerKey triggerKey) {
LOGGER.info("triggerResumed");
}
/**
* 一组触发器恢复执行
*/
@Override
public void triggersResumed(String triggerGroup) {
LOGGER.info("triggersResumed");
}
/**
* 任务被添加
*/
@Override
public void jobAdded(JobDetail jobDetail) {
LOGGER.info("jobAdded");
}
/**
* 任务被删除
*/
@Override
public void jobDeleted(JobKey jobKey) {
LOGGER.info("jobDeleted");
}
/**
* 任务暂停执行
*/
@Override
public void jobPaused(JobKey jobKey) {
LOGGER.info("jobPaused");
}
/**
* 一组任务暂停执行
*/
@Override
public void jobsPaused(String jobGroup) {
LOGGER.info("jobsPaused");
}
/**
* 任务恢复执行
*/
@Override
public void jobResumed(JobKey jobKey) {
LOGGER.info("jobResumed");
}
/**
* 一组任务恢复执行
*/
@Override
public void jobsResumed(String jobGroup) {
LOGGER.info("jobsResumed");
}
/**
* 调度器发生错误
*/
@Override
public void schedulerError(String msg, SchedulerException cause) {
LOGGER.info("schedulerError");
}
/**
* 调度器处于standby状态
*/
@Override
public void schedulerInStandbyMode() {
LOGGER.info("schedulerInStandbyMode");
}
/**
* 调度器已经启动
*/
@Override
public void schedulerStarted() {
LOGGER.info("schedulerStarted");
}
/**
* 调度器正在启动
*/
@Override
public void schedulerStarting() {
LOGGER.info("schedulerStarting");
}
/**
* 调度器已经关闭
*/
@Override
public void schedulerShutdown() {
LOGGER.info("schedulerShutdown");
}
/**
* 调度器正在关闭
*/
@Override
public void schedulerShuttingdown() {
LOGGER.info("schedulerShuttingdown");
}
/**
* 所有的任务、触发器、日历被删除
*/
@Override
public void schedulingDataCleared() {
LOGGER.info("schedulingDataCleared");
}
}
添加调度器监听器
public void addSchedulerListener(SchedulerListener schedulerListener);
具体属性参考官方文档
# ==================================== 调度器配置 ========================================
# 调度器名称(如果开启集群,每个实例的调度器名称必须相同)
org.quartz.scheduler.instanceName= MyScheduler
# 调度器实例ID(如果使用集群,实例ID必须唯一,设置成AUTO自动生成唯一ID)
org.quartz.scheduler.instanceId = AUTO
# 指定调度器每次最多可以获取触发器的数量(如果该值大于1,则acquireTriggersWithinLock必须设置true,避免出现脏数据)
org.quartz.scheduler.batchTriggerAcquisitionMaxCount = 3
# ==================================== 线程池配置 ========================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
# 指定是否从线程池中创建后台线程
org.quartz.threadPool.makeThreadsDaemons = false
org.quartz.threadPool.threadsInheritGroupOfInitializingThread = true
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = false
# 默认前缀名为调度器名_Worker
org.quartz.threadPool.threadNamePrefix
# ==================================== 持久化配置 ========================================
# 持久化方式(JobStoreTX:数据库;RAMJobStore:内存)
# org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
# 驱动委派类用来识别数据库系统的方言
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 用于数据源配置
org.quartz.jobStore.dataSource = myDS
# 数据库中Quartz相关表的前缀名
org.quartz.jobStore.tablePrefix = QRTZ_
# 设置true指定JobDataMap内部的value使用字符串形式存储
org.quartz.jobStore.useProperties = true
# 调度器容忍触发器错过执行的时间阈值(毫秒)
org.quartz.jobStore.misfireThreshold = 60000
# 是否开启集群功能
org.quartz.jobStore.isClustered = true
# 集群中实例的心跳检测的时间间隔
org.quartz.jobStore.clusterCheckinInterval = 15000
# 每次最多处理错过启动时间的触发器的数量
org.quartz.jobStore.maxMisfiresToHandleAtATime = 20
# 是否指定Quartz从数据源的连接中不调用setAutoCommit(false)
org.quartz.jobStore.dontSetAutoCommitFalse = false
# 加锁查询的SQL语句,{0}:tablePrefix,{1}:调度器的名字
org.quartz.jobStore.selectWithLockSQL = SELECT * FROM {0}LOCKS WHERE SCHED_NAME = {1} AND LOCK_NAME = ? FOR UPDATE
# 是否指定Quartz在数据库的连接中调用setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE)
org.quartz.jobStore.txIsolationLevelSerializable = false
# 获取下一个启动的触发器时是否加锁
org.quartz.jobStore.acquireTriggersWithinLock = false
# 用来创建Quartz内部的Semaphore实例
# org.quartz.jobStore.lockHandler.class
# 初始化时传递给驱动委派类的属性
# org.quartz.jobStore.driverDelegateInitString
# ===================================== 数据源配置 ========================================
# 数据库驱动的类名
org.quartz.dataSource.myDS.driver = com.mysql.cj.jdbc.Driver
# 数据库链接
org.quartz.dataSource.myDS.URL = jdbc:mysql://10.211.55.6:3306/quartz?useUnicode=true&characterEncoding=utf8&useSSL=false
# 数据库用户名
org.quartz.dataSource.myDS.user = root
# 数据库密码
org.quartz.dataSource.myDS.password = root
# 最大连接数
# org.quartz.dataSource.myDS.maxConnections = 10
# 指定用于数据源发现失败的或者错误的连接的SQL
# org.quartz.dataSource.myDS.validationQuery
# 执行上述SQL的时间间隔
# org.quartz.dataSource.myDS.idleConnectionValidationSeconds = 50
# 每次从池中获取连接时,是否应该执行用于验证连接的SQL,以此确保连接有效
# org.quartz.dataSource.myDS.validateOnCheckout = false
# 连接闲置多少秒时就丢弃该连接(0:表示禁用该功能)
# org.quartz.dataSource.myDS.discardIdleConnectionsSeconds = 0
Quartz 的集群保证了任务的高可用性,一旦某个节点出现问题,会有其它节点接替它继续执行任务。
Quartz 的集群中的各个节点不会直接通信,而是通过数据库来感知其它节点。
Quartz 的集群使用随机的负载均衡策略。集群中的节点会抢占获取DB锁,并由抢占成功的节点负责运行任务,这种方式会导致节点负载悬殊非常大。