quartz使用竟这么简单(上)

402 阅读5分钟

1.介绍

开源的任务调度框架,支持分布式。 用于有定时任务的需求时使用。例如淘宝购物时,从付款界面退出,订单会变成待支付订单,过十分钟会自动取消订单。

2.使用

引入依赖

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

主要的三部分 Job Trigger Scheduler

JobDetail:根据Job创建的实例,即为执行的任务

Trigger:用来设置任务的执行时间和频率

Schduler:将JobDetailTrigger联系起来,Trigger用来触发配套的JobDetail


JobBuilder:创建jobDetail 

TriggerBuilder:创建Trigger,有simpleTrigger创建简单的触发器,支持按照时间间隔执行任务。CronTrigger相对复杂的触发器,按照Cron表达式执行。 

SchedulerFactory:获取Scheduler


Crontrigger根据Cron表达式触发 

按照 秒分时天月周年 设置规则

周代表每月中的周

`*` 该单位下任意参数都执行 

`/` 相隔多长时间触发一次 , 分开相同单位下的触发时间

`-` 触发的范围 

`?` 在日和周上?代表不生效的单位

图片.png

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());
   }
}

图片.png

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());
    }
}

图片.png

    @Override
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
        System.out.println("trigger拒绝执行");
        return true;
    }

图片.png

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 存在以下几个实现类 匹配对应的规则进行绑定

图片.png

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进行匹配 

图片.png

NameMatcher主要是和group进行匹配 

图片.png

//添加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;
    ...... 省略部分代码
}

出现异常可执行的三种策略:

  1. refire 立即重新执行该异常

  2. unscheduleTrigg 本次执行的trigger取消关联不再执行

  3. 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;
        }
    }
}

图片.png

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;
        }
    }
}

图片.png

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;
        }
    }
}

图片.png