Quartz 定时任务使用 —— Trigger介绍(十二)

Quartz API核心接口有

  • Scheduler:(调度器)与scheduler交互的主要API; 

  • Job:(作业)你通过scheduler执行任务,你的任务类需要实现的接口; 

  • JobDetail:(作业实例)定义Job的实例; 

  • Trigger:(触发器)触发Job的执行; 

  • JobBuilder:定义和创建JobDetail实例的接口; 

  • TriggerBuilder:定义和创建Trigger实例的接口;

一、触发器接口基本介绍

// 触发器状态  
TriggerState  
    |-public enum TriggerState { NONE, NORMAL, PAUSED, COMPLETE, ERROR, BLOCKED }  
        |-NONE 无  
        |-NORMAL 正常状态  
        |-PAUSED 暂停状态   
        |-COMPLETE 完成  
        |-ERROR 错误
        |-BLOCKED 堵塞

// 执行完成时状态  
CompletedExecutionInstruction
    |-    public enum CompletedExecutionInstruction { 
            NOOP, RE_EXECUTE_JOB, SET_TRIGGER_COMPLETE, DELETE_TRIGGER, 
            SET_ALL_JOB_TRIGGERS_COMPLETE, SET_TRIGGER_ERROR, SET_ALL_JOB_TRIGGERS_ERROR }   
        |-NOOP 无   
        |-RE_EXECUTE_JOB 重复执行   
        |-SET_TRIGGER_COMPLETE 触发器执行完成  
        |-DELETE_TRIGGER 删除触发器  
        |-SET_ALL_JOB_TRIGGERS_COMPLETE 所有作业和触发器执行完成    
        |-SET_TRIGGER_ERROR 触发器执行错误  
        |-SET_ALL_JOB_TRIGGERS_ERROR 设置所有都是错误的  

TriggerTimeComparator  
getKey 获取触发器key值   
getJobKey  获取作业key 
getDescription 获取面熟  
getCalendarName 获取日历名称  
getJobDataMap 获取作业数据map  
getPriority 获取优先级  
mayFireAgain 是否重复执行  
getStartTime 开始时间  
getEndTime 结束时间  
getNextFireTime 下一次执行时间  
getPreviousFireTime 上一执行时间  
getFireTimeAfter(Date afterTime) 获取某个时间后的运行时间     
getFinalFireTime 获取最后执行时间  
getMisfireInstruction 获取失败策略  
getTriggerBuilder 获取触发器建造者    
getScheduleBuilder 获取调度类建造者 
equals 
compareTo

// 失败策略   
MISFIRE_INSTRUCTION_SMART_POLICY   
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY   
DEFAULT_PRIORITY

二、Trigger的公共属性

所有类型的trigger都有TriggerKey这个属性,表示trigger的身份;除此之外,trigger还有很多其它的公共属性。这些属性,在构建trigger的时候可以通过TriggerBuilder设置。

  • jobKey:当trigger触发时被执行的job的身份;

  • startTime:设置trigger第一次触发的时间。

  • endTime:表示trigger失效的时间点。比如,”每月第5天执行”的trigger,如果其endTime是6月1号,则其最后一次执行时间是6月5号。

其它的属性,会在下面的小节中解释。

priority:优先级

如果你的trigger很多(或者Quartz线程池的工作线程太少),Quartz可能没有足够的资源同时触发所有的trigger;这种情况下,你可能希望控制哪些trigger优先使用Quartz的工作线程,要达到该目的,可以在trigger上设置priority属性。比如,你有N个trigger需要同时触发,但只有Z个工作线程,优先级最高的Z个trigger会被首先触发。如果没有为trigger设置优先级,trigger使用默认优先级,值为5;priority属性的值可以是任意整数,正数、负数都可以。

注意:只有同时触发的trigger之间才会比较优先级。10:59触发的trigger总是在11:00触发的trigger之前执行。

注意:如果trigger是可恢复的,在恢复后再调度时,优先级与原trigger是一样的。

misfire:错过触发

trigger还有一个重要的属性misfire;如果scheduler关闭了,或者Quartz线程池中没有可用的线程来执行job,此时持久性的trigger就会错过(miss)其触发时间,即错过触发(misfire)。不同类型的trigger,有不同的misfire机制。它们默认都使用“智能机制(smart policy)”,即根据trigger的类型和配置动态调整行为。当scheduler启动的时候,查询所有错过触发(misfire)的持久性trigger。然后根据它们各自的misfire机制更新trigger的信息。当你在项目中使用Quartz时,你应该对各种类型的trigger的misfire机制都比较熟悉,这些misfire机制在JavaDoc中有说明。关于misfire机制的细节,会在讲到具体的trigger时作介绍。

calendar:日历

Quartz的Calendar对象(不是java.util.Calendar对象)可以在定义和存储trigger的时候与trigger进行关联。Calendar用于从trigger的调度计划中排除时间段。比如,可以创建一个trigger,每个工作日的上午9:30执行,然后增加一个Calendar,排除掉所有的商业节日。

排除指定节假日请阅读文章:Quartz 定时任务使用 —— 排除指定节假日时间执行任务(十一)

Trigger 触发器实现类

Trigger (org.quartz)    
    |-CalendarIntervalTrigger (org.quartz) 日期触发器   
    |   |-CalendarIntervalTriggerImpl (org.quartz.impl.triggers)  
    | 
    |-MutableTrigger (org.quartz.spi)   
    |   |-OperableTrigger (org.quartz.spi)    
    |       |-AbstractTrigger (org.quartz.impl.triggers)    
    |           |-CalendarIntervalTriggerImpl (org.quartz.impl.triggers)   
    |           |-SimpleTriggerImpl (org.quartz.impl.triggers)   
    |           |-DailyTimeIntervalTriggerImpl (org.quartz.impl.triggers)   
    |           |-CronTriggerImpl (org.quartz.impl.triggers)
    |
    |-SimpleTrigger (org.quartz) 简单触发器  
    |   |-SimpleTriggerImpl (org.quartz.impl.triggers)  
    |
    |-CoreTrigger (org.quartz.impl.triggers)  
    |   |-CalendarIntervalTriggerImpl (org.quartz.impl.triggers)   
    |   |-SimpleTriggerImpl (org.quartz.impl.triggers)   
    |   |-DailyTimeIntervalTriggerImpl (org.quartz.impl.triggers)  
    |   |-CronTriggerImpl (org.quartz.impl.triggers)
    |
    |-CronTrigger (org.quartz) cron表达式   
    |   |-CronTriggerImpl (org.quartz.impl.triggers)  
    |
    |-DailyTimeIntervalTrigger (org.quartz)日期触发类(日)    
        |-DailyTimeIntervalTriggerImpl (org.quartz.impl.triggers)

常用的触发器有下面四个

  • SimpleTrigger:简单的触发器 

  • CalendarIntervalTrigger:日历触发器 

  • CronTrigger:Cron表达式触发器 

  • DailyTimeIntervalTrigger:日期触发器

三、调度器建造者

这里源码中利用了建造者模式

// 用于创建各个调度器  
ScheduleBuilder (org.quartz)   
    |-CalendarIntervalScheduleBuilder (org.quartz)    
    |-DailyTimeIntervalScheduleBuilder (org.quartz)   
    |-SimpleScheduleBuilder (org.quartz)       
    |-CronScheduleBuilder (org.quartz)

ScheduleBuilder

private TriggerBuilder() 构造函数私有  

public static TriggerBuilder<Trigger> newTrigger()  创建一个建造者

build() 创建触发器

// 根据name和默认的group(即"DEFAULT_GROUP")创建trigger的key
public TriggerBuilder<T> withIdentity(String name) 
public TriggerBuilder<T> withIdentity(String name, String group)
public TriggerBuilder<T> withIdentity(TriggerKey triggerKey)

// 描述
public TriggerBuilder<T> withDescription(String triggerDescription) 
// 优先级 
public TriggerBuilder<T> withPriority(int triggerPriority) 
//日期
public TriggerBuilder<T> modifiedByCalendar(String calName) 
//开始时间
public TriggerBuilder<T> startAt(Date triggerStartTime) 
//立即执行
public TriggerBuilder<T> startNow() 
//结束时间
public TriggerBuilder<T> endAt(Date triggerEndTime) 
//调度器
public <SBT extends T> TriggerBuilder<SBT> withSchedule(ScheduleBuilder<SBT> schedBuilder) 
//设置作业
public TriggerBuilder<T> forJob(JobKey keyOfJobToFire) 
public TriggerBuilder<T> forJob(String jobName)
public TriggerBuilder<T> forJob(String jobName, String jobGroup)
public TriggerBuilder<T> forJob(JobDetail jobDetail)
usingJobData(----,----) 设置作业内容

key
description
startTime
endTime
priority Trigger.DEFAULT_PRIORITY 
calendarName
jobKey
jobDataMap
scheduleBuilder

SimpleScheduleBuilder 简单的调度器创建者

分析源码中的方法和属性

//构造函数私有化
protected SimpleScheduleBuilder() 

//获取简单调度器
public static SimpleScheduleBuilder simpleSchedule()

/***********************/
// 1分钟执行(一直执行)   
public static SimpleScheduleBuilder repeatMinutelyForever() 
//每隔几分钟执行(一直执行)   
public static SimpleScheduleBuilder repeatMinutelyForever(int minutes) 
// 1秒执行(一直执行)      
public static SimpleScheduleBuilder repeatSecondlyForever() 
//每隔几秒钟执行(一直执行)   
public static SimpleScheduleBuilder repeatSecondlyForever(int seconds) 
// 1小时执行(一直执行)   
public static SimpleScheduleBuilder repeatHourlyForever() 
//每隔几小时钟执行(一直执行) 
public static SimpleScheduleBuilder repeatHourlyForever(int hours)  
 
/***********************/
//间隔时间为1分钟,总的执行次数为count
public static SimpleScheduleBuilder repeatMinutelyForTotalCount(int count)
//间隔时间为几分钟,总的执行次数为count   .............
public static SimpleScheduleBuilder repeatMinutelyForTotalCount(int count, int minutes)
public static SimpleScheduleBuilder repeatSecondlyForTotalCount(int count)
public static SimpleScheduleBuilder repeatSecondlyForTotalCount(int count, int seconds)
public static SimpleScheduleBuilder repeatHourlyForTotalCount(int count)
public static SimpleScheduleBuilder repeatHourlyForTotalCount(int count, int hours)

/***********************/
public MutableTrigger build() 创建一个Trigger

/***********************/
// 几秒钟重复执行   
public SimpleScheduleBuilder withIntervalInMilliseconds(long intervalInMillis)
public SimpleScheduleBuilder withIntervalInSeconds(int intervalInSeconds)
public SimpleScheduleBuilder withIntervalInMinutes(int intervalInMinutes)
public SimpleScheduleBuilder withIntervalInHours(int intervalInHours)

/***********************/
 // 重复执行册数  
public SimpleScheduleBuilder withRepeatCount(int triggerRepeatCount)

/***********************/
参考地址  
http://blog.sina.com.cn/s/blog_56d8ea900101eu45.html
//以错过的第一个频率时间立刻开始执行
//重做错过的所有频率周期后
//当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行
public SimpleScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires()

//以当前时间为触发频率立即触发执行
//执行至FinalTIme的剩余周期次数
//以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
//调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
public SimpleScheduleBuilder withMisfireHandlingInstructionFireNow()

//不触发立即执行
//等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
//以startTime为基准计算周期频率,并得到FinalTime
//即使中间出现pause,resume以后保持FinalTime时间不变
public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithExistingCount()

//不触发立即执行
//等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
//以startTime为基准计算周期频率,并得到FinalTime
//即使中间出现pause,resume以后保持FinalTime时间不变
public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithRemainingCount()

//以当前时间为触发频率立即触发执行
//执行至FinalTIme的剩余周期次数
//以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
//调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithExistingCount()

//以当前时间为触发频率立即触发执行
//执行至FinalTIme的剩余周期次数
//以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithRemainingCount()

interval 时间间隔
repeatCount 重复时间
misfireInstruction

CronScheduleBuilder Corn调度器创建者

源码分析

// 构造函数私有化
protected CronScheduleBuilder(CronExpression cronExpression)、

public MutableTrigger build()

// 根据cron表达式建造
public static CronScheduleBuilder cronSchedule(String cronExpression)

// 核查表达式是否正确
public static CronScheduleBuilder cronScheduleNonvalidatedExpression(String cronExpression) throws ParseException
            
//表达式异常
cronScheduleNoParseException

// 利用CronExpression建造
public static CronScheduleBuilder cronSchedule(CronExpression cronExpression)

//每天在指定的时间执行,根据这个调度创建一个cron表达式
public static CronScheduleBuilder dailyAtHourAndMinute(int hour, int minute)

// 通过`分钟`、`小时`、`周`创建一个CronScheduleBuilder实例,即在某一天的给定时刻
// (通过`分钟`、`小时`指定)执行,,而天数由`周`确定,如果“周二、周四的10:05“等;
public static CronScheduleBuilder atHourAndMinuteOnGivenDaysOfWeek(int hour, int minute, Integer... daysOfWeek)
            
//调度计划:每周的某一天,在指定的时间(小时和分钟)执行
public static CronScheduleBuilder weeklyOnDayAndHourAndMinute(int dayOfWeek, int hour, int minute)

//调度计划:每月的某一天,在指定的时间(小时和分钟)执行
public static CronScheduleBuilder monthlyOnDayAndHourAndMinute(int dayOfMonth, int hour, int minute)

//设置时区
public CronScheduleBuilder inTimeZone(TimeZone timezone)

// 设置处理办法
public CronScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires() 
public CronScheduleBuilder withMisfireHandlingInstructionDoNothing()
public CronScheduleBuilder withMisfireHandlingInstructionFireAndProceed()

cronExpression
misfireInstruction

CalendarIntervalScheduleBuilder 日历间隔计划生成器 

CalendarIntervalScheduleBuilder
calendarIntervalSchedule
build

// 和DailyTimeIntervalScheduleBuilder差不多
public CalendarIntervalScheduleBuilder withInterval(int timeInterval, IntervalUnit unit)
withIntervalInSeconds
withIntervalInMinutes
withIntervalInHours
withIntervalInDays
withIntervalInWeeks
withIntervalInMonths
withIntervalInYears

withMisfireHandlingInstructionIgnoreMisfires
withMisfireHandlingInstructionDoNothing
withMisfireHandlingInstructionFireAndProceed
inTimeZone

preserveHourOfDayAcrossDaylightSavings
skipDayIfHourDoesNotExist
validateInterval
interval
intervalUnit
misfireInstruction
timeZone
preserveHourOfDayAcrossDaylightSavings
skipDayIfHourDoesNotExist

DailyTimeIntervalScheduleBuilder

DailyTimeIntervalScheduleBuilder()

dailyTimeIntervalSchedule()

build()

withInterval(int timeInterval, IntervalUnit unit) //执行时间间隔触发执行,unit时间单位 
withIntervalInSeconds(int intervalInSeconds)    //秒 
withIntervalInMinutes(int intervalInMinutes)    //分钟 
withIntervalInHours(int intervalInHours)    //小时 

// 周几执行 
onDaysOfTheWeek(Set<Integer> onDaysOfWeek)
onDaysOfTheWeek(Integer... onDaysOfWeek)

onMondayThroughFriday()
onSaturdayAndSunday()
onEveryDay()

startingDailyAt(TimeOfDay timeOfDay)    // 开始触发时间 
endingDailyAt(TimeOfDay timeOfDay)    //结束时间 
endingDailyAfterCount(int count)    

withMisfireHandlingInstructionIgnoreMisfires()
withMisfireHandlingInstructionDoNothing()
withMisfireHandlingInstructionFireAndProceed()

//重复次数 
withRepeatCount() 
validateInterval()

// 常量等 
interval 
intervalUnit 
daysOfWeek 
startTimeOfDay 
endTimeOfDay 
repeatCount 
misfireInstruction 
ALL_DAYS_OF_THE_WEEK 
MONDAY_THROUGH_FRIDAY 
SATURDAY_AND_SUNDAY

四、Trigger实现类

Quartz有以下几种Trigger实现:

1、SimpleTrigger

正如类名说介绍的,一个quartz简单的触发器。指定从某一个时间开始,以一定的时间间隔(单位是毫秒)执行的任务。

它适合的任务类似于:9:00 开始,每隔1小时,每隔几分钟,每隔几秒钟执行一次。

它的属性有:

  • repeatInterval:重复间隔

  • repeatCount:重复次数。实际执行次数是 repeatCount+1。因为在startTime的时候一定会执行一次。

官网介绍:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/tutorial-lesson-05.html

例子:

import org.quartz.*;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleTriggerMain {
    public static void main(String[] args) throws SchedulerException {
        // 获取一个调度工厂
        SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
        // 获取一个调度器
        Scheduler sched = schedFact.getScheduler();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
        // 在当前时间15秒后运行
        Date startTime = DateBuilder.nextGivenSecondDate(new Date( ),15);
        // 创建一个SimpleTrigger实例,指定该Trigger在Scheduler中所属组及名称。
        // 接着设置调度的时间规则.当前时间15秒后运行,每10秒运行一次,共运行5次
        SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
                .startAt(startTime).withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .withRepeatCount(5)
                )
                .build();
        sched.scheduleJob(job, trigger);
        // 调度启动
        sched.start();
    }
}

2、CalendarIntervalTrigger

类似于SimpleTrigger,指定从某一个时间开始,以一定的时间间隔执行的任务。 但是不同的是SimpleTrigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每月的时间间隔不是固定值),而CalendarIntervalTrigger支持的间隔单位有秒,分钟,小时,天,月,年,星期。

相较于SimpleTrigger有两个优势:

1、更方便,比如每隔1小时执行,你不用自己去计算1小时等于多少毫秒。

2、支持不是固定长度的间隔,比如间隔为月和年。但劣势是精度只能到秒。

它适合的任务类似于:9:00 开始执行,并且以后每周 9:00 执行一次

它的属性有:

  • interval:执行间隔

  • intervalUnit:执行间隔的单位(秒,分钟,小时,天,月,年,星期)

例子:

// 每两秒执行
CalendarIntervalTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(
        CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withInterval(2, DateBuilder.IntervalUnit.SECOND)
).build();

3、DailyTimeIntervalTrigger

指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。

它适合的任务类似于:指定每天9:00 至 18:00 ,每隔70秒执行一次,并且只要周一至周五执行。

它的属性有:

  • startTimeOfDay:每天开始时间

  • endTimeOfDay:每天结束时间

  • daysOfWeek:需要执行的星期

  • interval:执行间隔

  • intervalUnit:执行间隔的单位(秒,分钟,小时,天,月,年,星期)

  • repeatCount:重复次数

例子:

DailyTimeIntervalTrigger trigger = dailyTimeIntervalSchedule()
    .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) // 第天9:00开始
    .endingDailyAt(TimeOfDay.hourAndMinuteOfDay(16, 0)) // 16:00 结束 
    .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) // 周一至周五执行
    .withIntervalInHours(1) // 每间隔1小时执行一次
    .withRepeatCount(100) // 最多重复100次(实际执行100+1次)
    .build();
    
DailyTimeIntervalTrigger trigger = dailyTimeIntervalSchedule()
    .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) // 第天9:00开始
    .endingDailyAfterCount(10) // 每天执行10次,这个方法实际上根据 startTimeOfDay+interval*count 算出 endTimeOfDay
    .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) // 周一至周五执行
    .withIntervalInHours(1) // 每间隔1小时执行一次
    .build();
    
// 每两秒执行
DailyTimeIntervalTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(
        DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule().withInterval(2, DateBuilder.IntervalUnit.SECOND)
).build();

4、CronTrigger

适合于更复杂的任务,它支持类型于Linux Cron的语法(并且更强大)。基本上它覆盖了以上三个Trigger的绝大部分能力(但不是全部)

CronTrigger 允许设定非常复杂的触发时间表。然而有时也许不得不使用两个或多个 SimpleTrigger 来满足你的触发需求,这时候你仅仅需要一个CronTrigger 实例就够了。

它的属性只有:

例子:

 // 每两秒执行
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(
        CronScheduleBuilder.cronSchedule("/2 * * * * ?")
).build();

5、NthIncludedDayTrigger

org.quartz.NthIncludedDayTrigger 是 Quartz 开发团队最新加入到框架中的一个 Trigger。它设计用于在每一间隔类型的第几天执行 Job。例如,你要在每个月的 15 号执行开票的 Job,用 NthIncludedDayTrigger 就再合适不过了。Quartz 的 Caldendar 也可与 Trigger 关联以此把周末与节假日考虑进来,并在必要时跳开这些日期。接下来的代码片断描绘了如何创建一个 NthIncludedDayTrigger.

NthIncludedDayTrigger trigger = new NthIncludedDayTrigger("MyTrigger", Scheduler.DEFAULT_GROUP);
trigger.setN(15);
trigger.setIntervalType(NthIncludedDayTrigger.INTERVAL_TYPE_MONTHLY);

...

...

...


文档参考:http://blog.csdn.net/QXC1281/article/details/68924140


赞(52) 打赏
未经允许不得转载:优客志 » JAVA开发

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏