BaseCalendar

专门用于屏蔽一个时间区间,使Trigger在这个区间中不被触发

AnnualCalendar

排除每一年中指定的一天或多少天,精度是天

CronCalendar

使用表达式排除某些时间段不执行,精度取决于Cron表达式,最大精度到秒

DailyCalendar

指定的时间范围内的每一天不执行,指定每天的时间段,格式是HH:MM[:SS[mmm]],即最大精度可以到毫秒

HolidayCalendar

排除节假日,精度到天

MonthlyCalendar

排除月份中的数天,可选值为1-31,精度是天

WeeklyCalendar

排除星期中的一天或多天,可选值比如为:java.util.Calendar.SUNDAY,精度是天

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class CalendarSchedule {
public static void main(String[] args) throws SchedulerException {
//创建一个JobDetail的实例,将该实例与HelloJob绑定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("test")
.build();
AnnualCalendar holidays = new AnnualCalendar();
// 排除今天的时间2017年11月27日(月份是从0~11的)
GregorianCalendar nationalDay = new GregorianCalendar(2017, 10, 27);
// 排除的日期,如果为false则为包含
holidays.setDayExcluded(nationalDay,true);

Trigger simpleTrigger = TriggerBuilder.newTrigger()
.withIdentity("testTrigger")
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)
.repeatForever()) //每一秒执行一次job
.modifiedByCalendar("holidays") //将我们设置好的Calander与trigger绑定
.build();

//创建Scheduler实例
StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = stdSchedulerFactory.getScheduler();
//向Scheduler注册日历
scheduler.addCalendar("holidays",holidays,false,false);
//让trigger应用指定的日历规则
scheduler.scheduleJob(jobDetail,simpleTrigger);
scheduler.start();
}
}

定时任务增删改查

参考Scheduler源码中的方法

1
2
3
4
5
6
7
8
#定时任务
quartz:
jobs:
- name: myName #(随便取任务名)
group: collect
cron: 0 0/5 * * * ? *
jobClass: com.gamer.me.quartz.jobs.MyJob #(自己的定时任务的执行类,也就是你写业务代码的类)
desc: 我的任务
1
2
3
4
5
6
7
8
9
@Data
public class SchedulerJob {

private String name;
private String group;
private String cron;
private String jobClass;
private String desc;
}
1
2
3
4
5
6
7
@Data
@Component
@ConfigurationProperties(prefix = "quartz")
public class SchedulerJobs {

private List<SchedulerJob> jobs;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
@Slf4j
@Component
public class SchedulerManager {

@Autowired
private Scheduler scheduler;

/**
* 激活任务
* @param schedulerJob
*/
public void activeJob(SchedulerJob schedulerJob){
JobKey jobKey = JobKey.jobKey(schedulerJob.getName(), schedulerJob.getGroup());
try {
if (scheduler.checkExists(jobKey) && !MonitorCronJob.JOB_NAME.equals(schedulerJob.getName())) {
updateJob(schedulerJob);
}else {
createJob(schedulerJob);
}
} catch (SchedulerException e) {
logger.error("activeJob {}", e);
}
}

/**
* 创建任务并加入调度
* @param schedulerJob
*/
public void createJob(SchedulerJob schedulerJob){
JobKey jobKey = JobKey.jobKey(schedulerJob.getName(), schedulerJob.getGroup());
try {
if (scheduler.checkExists(jobKey)) {
return;
}
Class<?> clazz = Class.forName(schedulerJob.getJobClass());
JobDetail jobDetail = getJobDetail(schedulerJob, (Class<Job>) clazz);
Trigger cronTrigger = getCronTrigger(schedulerJob);
//加入调度器
scheduler.scheduleJob(jobDetail, cronTrigger);
} catch (ClassNotFoundException | SchedulerException e) {
logger.error("createJob {}", e);
}
}

/**
* 更新任务触发器
* @param schedulerJob
*/
public void updateJob(SchedulerJob schedulerJob){
TriggerKey triggerKey = TriggerKey.triggerKey(schedulerJob.getName(), schedulerJob.getGroup());
try {
Trigger trigger = scheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
JobKey jobKey = trigger.getJobKey();
//查询cron
String oldCron = ((CronTrigger)trigger).getCronExpression();
//没有变化则返回
if (oldCron.equals(schedulerJob.getCron())){
return;
}
Trigger cronTrigger = getCronTrigger(schedulerJob);
//加入调度器
scheduler.rescheduleJob(triggerKey, cronTrigger);
} catch (SchedulerException e) {
logger.error("updateJob {}", e);
}
}

/**
* 删除任务
*/
public void deleteJobs(List<JobKey> jobKeys) {
try {
scheduler.deleteJobs(jobKeys);
} catch (SchedulerException e) {
logger.error("deleteJobs {}", e);
}
}

/**
* 创建任务
* @param schedulerJob
* @param clazz
* @return
*/
private JobDetail getJobDetail(SchedulerJob schedulerJob, Class<Job> clazz) {
return JobBuilder.newJob()
.ofType(clazz)
.withIdentity(schedulerJob.getName(), schedulerJob.getGroup())
.withDescription(schedulerJob.getDesc())
.build();
}

/**
* 创建触发器
* @param schedulerJob
* @return
*/
private Trigger getCronTrigger(SchedulerJob schedulerJob) {
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(schedulerJob.getCron());
if (!MonitorCronJob.JOB_NAME.equals(schedulerJob.getName())){
//任务错过执行策略,以错过的第一个频率时间立刻开始执行,重做错过的所有频率周期后,当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行
cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
}
return TriggerBuilder.newTrigger()
.withIdentity(schedulerJob.getName(), schedulerJob.getGroup())
.withDescription(schedulerJob.getDesc())
.withSchedule(cronScheduleBuilder)
.build();
}
}

监控其他定时任务的总任务MonitorCronJob(用于监控cron的更新)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Slf4j
public class MonitorCronJob implements Job {

public static final String JOB_NAME = "monitor_cron";
public static final String GROUP_NAME = "monitor";
public static final String CRON = "0 0/10 * * * ?";
public static final String DESC = "监控cron更新";

@Autowired
private SchedulerManager schedulerManager;
@Autowired
private SchedulerJobs schedulerJobs;
@Autowired
private ContextRefresher contextRefresher;

@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//重新加载配置
contextRefresher.refresh();
Set<JobKey> oldJobKeys = null;
try {
oldJobKeys = jobExecutionContext.getScheduler().getJobKeys(GroupMatcher.anyJobGroup());
} catch (SchedulerException e) {
logger.error("MonitorCronJob {}", e);
}

List<String> newJobKeys = new ArrayList<>();
for (SchedulerJob job : schedulerJobs.getJobs()) {
//过滤掉monitor_cron任务
if (job.getName().equals(JOB_NAME)) {
continue;
}
newJobKeys.add(job.getName());
logger.info("job【{}】,cron【{}】", job.getName(), job.getCron());
schedulerManager.activeJob(job);
}
if (oldJobKeys == null) {
return;
}
//删除没有配置的任务
List<JobKey> shouldDeleteJobKeys = oldJobKeys.stream()
.filter(jobKey -> !JOB_NAME.equals(jobKey.getName()) && !newJobKeys.contains(jobKey.getName()))
.collect(Collectors.toList());
logger.info("delete jobs {}", shouldDeleteJobKeys);
schedulerManager.deleteJobs(shouldDeleteJobKeys);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Component
public class Initialization implements ApplicationRunner {

@Autowired
private SchedulerManager schedulerManager;

@Override
public void run(ApplicationArguments args) throws Exception {
SchedulerJob schedulerJob = new SchedulerJob();
schedulerJob.setName(MonitorCronJob.JOB_NAME);
schedulerJob.setGroup(MonitorCronJob.GROUP_NAME);
schedulerJob.setCron(MonitorCronJob.CRON);
schedulerJob.setDesc(MonitorCronJob.DESC);
schedulerJob.setJobClass(MonitorCronJob.class.getName());
schedulerManager.activeJob(schedulerJob);
}
}