1.介绍
开源的任务调度框架,支持分布式。 用于有定时任务的需求时使用。例如淘宝购物时,从付款界面退出,订单会变成待支付订单,过十分钟会自动取消订单。
2.使用
引入依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
主要的三部分 Job
Trigger
Scheduler
JobDetail:根据Job创建的实例,即为执行的任务
Trigger:用来设置任务的执行时间和频率
Schduler:将JobDetail和Trigger联系起来,Trigger用来触发配套的JobDetail
JobBuilder:创建jobDetail
TriggerBuilder:创建Trigger,有simpleTrigger创建简单的触发器,支持按照时间间隔执行任务。CronTrigger相对复杂的触发器,按照Cron表达式执行。
SchedulerFactory:获取Scheduler
Crontrigger根据Cron表达式触发
按照 秒分时天月周年 设置规则
周代表每月中的周
`*` 该单位下任意参数都执行
`/` 相隔多长时间触发一次 , 分开相同单位下的触发时间
`-` 触发的范围
`?` 在日和周上?代表不生效的单位
3.demo
//需要执行的job需要实现Job接口
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("hello world");
}
}
//simpleTrigger执行任务
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(10)).build();
StdSchedulerFactory.getDefaultScheduler().scheduleJob(job, trigger);
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
//Crontrigger执行任务
JobDetail jobDetail = JobBuilder.newJob(JobTest.class).withIdentity("job1", "group1").build();
CronTrigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("*/2 * * * * ?")).withIdentity("trigger1", "group1").build();
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
4.常用的service方法
简单列举一些方法,其他需要的自行添加
public interface QuartzService {
//添加job
public void addJob(String jobName, String jobGroupName, String cronExpression, Map<String, String> map) throws Exception;
//暂停job
public void jobPause(String jobName, String jobGroupName) throws Exception;
//恢复job
public void jobResume(String jobName, String jobGroupName) throws Exception;
//重新启动trigger
public void jobReschedule(String jobName, String jobGroupName, String cronExpression) throws Exception;
//删除job
public void jobDelete(String jobName, String jobGroupName) throws Exception;
//检查job是否存在
public boolean checkExist(String jobName, String jobGroupName) throws Exception;
//暂停所有job
public void jobPauseAll() throws Exception;
//恢复所有job
public void jobResumeAll() throws Exception;
//获取所有job的name
public List<String> getAllJobName(String jobGroupName) throws Exception;
}
实现方法 基本对应着schedulerListener的方法
public class QuartzServiceImpl implements QuartzService {
@Autowired
@Qualifier("scheduler")
private Scheduler scheduler;
@Override
public void addJob(String jobName, String jobGroupName, String cronExpression, Map<String, String> map) throws Exception {
scheduler.start();
Job job = (Job)Class.forName(jobName).newInstance();
JobDetail jobDetail = JobBuilder.newJob(job.getClass()).withIdentity(jobName, jobGroupName).build();
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName).withSchedule(cronScheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
}
@Override
public void jobPause(String jobName, String jobGroupName) throws Exception {
scheduler.pauseJob(JobKey.jobKey(jobName,jobGroupName));
}
@Override
public void jobResume(String jobName, String jobGroupName) throws Exception {
scheduler.resumeJob(JobKey.jobKey(jobName,jobGroupName));
}
@Override
public void jobReschedule(String jobName, String jobGroupName, String cronExpression) throws Exception {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger trigger = (CronTrigger)scheduler.getTrigger(triggerKey);
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
scheduler.rescheduleJob(triggerKey, trigger);
}
@Override
public void jobDelete(String jobName, String jobGroupName) throws Exception {
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
}
@Override
public boolean checkExist(String jobName, String jobGroupName) throws Exception {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
return scheduler.checkExists(triggerKey);
}
@Override
public void jobPauseAll() throws Exception {
scheduler.pauseAll();
}
@Override
public void jobResumeAll() throws Exception {
scheduler.resumeAll();
}
@Override
public List<String> getAllJobName(String jobGroupName) throws Exception {
List<String> arrayList = new ArrayList<>();
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(jobGroupName));
for (JobKey jobKey : jobKeys) {
arrayList.add(jobKey.getName());
}
return arrayList;
}
}
5.Listener
监听器,不同类型的监听器会在监听不同对象的动作,并可以做出相应的反应。例如jobListener可以在job执行的时候,做出相应的动作。
5.1 JobListener
//job监听器,实现该接口即可
public interface JobListener {
//监听器的名字
String getName();
//job被执行之前
void jobToBeExecuted(JobExecutionContext var1);
//jon被TriggerListener拒绝执行之后,在triggerListener中会有体现
void jobExecutionVetoed(JobExecutionContext var1);
//job执行之后
void jobWasExecuted(JobExecutionContext var1, JobExecutionException var2);
}
@AllArgsConstructor
public class MyJobListener implements JobListener {
private String name;
@Override
public String getName() {
return name;
}
@Override
public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
System.out.println("即将执行"+jobExecutionContext.getJobDetail().getKey().getName());
System.out.println("即将执行"+jobExecutionContext.getJobDetail().getKey().getGroup());
}
@Override
public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
System.out.println("被触发器拒绝");
}
@Override
public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
System.out.println("执行过后"+jobExecutionContext.getJobDetail().getKey().getName());
System.out.println("执行过后"+jobExecutionContext.getJobDetail().getKey().getGroup());
}
}
5.2 TriggerListener
//trigger监听器
public interface TriggerListener {
String getName();
//触发器执行job之前
void triggerFired(Trigger var1, JobExecutionContext var2);
//返回false表示触发器执行job,返回true表示拒绝
boolean vetoJobExecution(Trigger var1, JobExecutionContext var2);
//触发器错过触发时机
void triggerMisfired(Trigger var1);
//触发完成之后
void triggerComplete(Trigger var1, JobExecutionContext var2, Trigger.CompletedExecutionInstruction var3);
}
@AllArgsConstructor
public class MyTriggerListener implements TriggerListener {
private String name;
@Override
public String getName() {
return name;
}
@Override
public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) {
System.out.println("trigger执行前"+trigger.getKey().getName());
System.out.println("trigger执行前"+trigger.getKey().getGroup());
}
@Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
return false;
}
@Override
public void triggerMisfired(Trigger trigger) {
}
@Override
public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {
System.out.println("trigger执行完成后"+trigger.getKey().getName());
System.out.println("trigger执行完成后"+trigger.getKey().getGroup());
}
}
@Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
System.out.println("trigger拒绝执行");
return true;
}
5.3 SchdulerListener
与job,tigger添加,删除等相关,scheduler开始暂停相关
public interface SchedulerListener {
void jobScheduled(Trigger var1);
void jobUnscheduled(TriggerKey var1);
void triggerFinalized(Trigger var1);
void triggerPaused(TriggerKey var1);
void triggersPaused(String var1);
void triggerResumed(TriggerKey var1);
void triggersResumed(String var1);
void jobAdded(JobDetail var1);
void jobDeleted(JobKey var1);
void jobPaused(JobKey var1);
void jobsPaused(String var1);
void jobResumed(JobKey var1);
void jobsResumed(String var1);
void schedulerError(String var1, SchedulerException var2);
void schedulerInStandbyMode();
void schedulerStarted();
void schedulerStarting();
void schedulerShutdown();
void schedulerShuttingdown();
void schedulingDataCleared();
}
5.4 监听器绑定
创建了以上监听器如何绑定生效。
Matcher 存在以下几个实现类 匹配对应的规则进行绑定
andMatcher 传参多个matcher,为and的关系
//参数为Matcher,取交集结果
AndMatcher.and()
//参数为Matcher,取并集结果
OrMatcher.or()
KeyMatcher 根据JobKey进行比较
//根据传参进行匹配,对jobListener使用
KeyMatcher.keyEquals(JobKey jobKey)
EverythingMatcher 匹配所有的key,匹配所有的trigger
//匹配所有的job
EverythingMatcher.allJobs();
//匹配所有的触发器
EverythingMatcher.allTriggers();
//参数为Matcher,去除参数中匹配的Matcher
NotMatcher.not()
GroupMatcher主要是和group进行匹配
NameMatcher主要是和group进行匹配
//添加jobListener
scheduler.getListenerManager().addJobListener(new MyJobListener(jobDetail.getKey().getName()), KeyMatcher.keyEquals(JobKey.jobKey("name","group")));
//添加triggerListener
scheduler.getListenerManager().addTriggerListener(new MyTriggerListener(trigger.getKey().getName()), NameMatcher.nameEquals("group"));
//添加schedulerListener
scheduler.getListenerManager().addSchedulerListener(new MySchedulerListener());
6.异常处理
public class JobExecutionException extends SchedulerException {
private boolean refire = false;
private boolean unscheduleTrigg = false;
private boolean unscheduleAllTriggs = false;
...... 省略部分代码
}
出现异常可执行的三种策略:
-
refire 立即重新执行该异常
-
unscheduleTrigg 本次执行的trigger取消关联不再执行
-
unscheduleAllTriggs 与该job相关的trigger全部取消关联,不再执行
1. refire 立即重新执行该异常
设定执行动作:任务不重复的执行一次
结果:无限执行任务并报错
//正常情况只执行一次任务
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetail jobDetail = JobBuilder.newJob(JobTest.class).withIdentity("job1", "group1").build();
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1","group1").withSchedule(SimpleScheduleBuilder.simpleSchedule()).build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
public class JobTest implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("执行job");
try{
int i = 1 / 0;
}catch (Exception e){
JobExecutionException jobExecutionException = new JobExecutionException(e);
jobExecutionException.setRefireImmediately(Boolean.TRUE);
throw jobExecutionException;
}
}
}
2.unscheduleTrigg 本次执行的trigger取消关联不再执行
设定执行动作:两个触发器无限重复执行一个任务,并且第二个触发器晚两秒执行
结果:两个触发器各执行一次
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetail jobDetail = JobBuilder.newJob(JobTest.class).withIdentity("job1", "group1").build();
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1","group1").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build();
Date date = new Date();
date.setTime(date.getTime()+2000);
SimpleTrigger trigger1 = TriggerBuilder.newTrigger().withIdentity("trigger2","group1").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).startAt(date).build();
Set<Trigger> set = new HashSet<>();
set.add(trigger);
set.add(trigger1);
scheduler.scheduleJob(jobDetail, set, Boolean.TRUE);
scheduler.start();
public class JobTest implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("执行job");
try{
int i = 1 / 0;
}catch (Exception e){
JobExecutionException jobExecutionException = new JobExecutionException(e);
jobExecutionException.setUnscheduleFiringTrigger(Boolean.TRUE);
throw jobExecutionException;
}
}
}
3. unscheduleAllTriggs 与该job相关的trigger全部取消关联,不再执行
设定执行动作:两个触发器无限重复执行一个任务,并且第二个触发器晚两秒执行
结果:一个触发器执行一次
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetail jobDetail = JobBuilder.newJob(JobTest.class).withIdentity("job1", "group1").build();
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1","group1").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build();
Date date = new Date();
date.setTime(date.getTime()+2000);
SimpleTrigger trigger1 = TriggerBuilder.newTrigger().withIdentity("trigger2","group1").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).startAt(date).build();
Set<Trigger> set = new HashSet<>();
set.add(trigger);
set.add(trigger1);
scheduler.scheduleJob(jobDetail, set, Boolean.TRUE);
scheduler.start();
public class JobTest implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("执行job");
try{
int i = 1 / 0;
}catch (Exception e){
JobExecutionException jobExecutionException = new JobExecutionException(e);
jobExecutionException.setUnscheduleAllTriggers(Boolean.TRUE);
throw jobExecutionException;
}
}
}