quartz基础学习(二)

本文详细介绍了Quartz框架中的SimpleTrigger和CronTrigger的使用,包括无状态与有状态Job的区别,SimpleTrigger的调度需求和Misfire策略,以及CronTrigger的日历表示法和Missfire策略。示例代码展示了如何配置和创建各种触发器,帮助理解这两种类型的Trigger在实际应用中的不同场景。
摘要由CSDN通过智能技术生成

转载:https://blog.csdn.net/jiangliubang/article/details/78508101  

五、SimpleTrigger
0、有状态的job与无状态的job:无状态任务在执行时,拥有自己的JobDataMap拷贝,对JobData的更改不会影响下次的执行。而有状态任务共享同一个JobDataMap实例,每次任务执行对JobDataMap所做的更改都会保存下来,后面的执行可以看到这个更改。也就是每次执行任务后都会对后面的执行发生影响。正因为这个原因,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行,这意味着如果前次的StatefulJob还没有执行完毕,下一次的任务将阻塞等待,直到前次任务执行完毕。有状态任务比无状态任务需要考虑更多的因素,程序往往拥有更高的复杂度,因此除非必要,应该尽量使用无状态的Job。
1、SimpleTrigger可以满足的调度需求是:在具体的时间点执行一次,或者在具体的时间点执行,并且以指定的间隔重复执行若干次。比如,你有一个trigger,你可以设置它在2015年1月13日的上午11:23:54准时触发,或者在这个时间点触发,并且每隔2秒触发一次,一共重复5次。根据描述,你可能已经发现了,SimpleTrigger的属性包括:开始时间、结束时间、重复次数以及重复的间隔。这些属性的含义与你所期望的是一致的,只是关于结束时间有一些地方需要注意。重复次数,可以是0、正整数,以及常量SimpleTrigger.REPEAT_INDEFINITELY。重复的间隔,必须是0,或者long型的正数,表示毫秒。注意,如果重复间隔为0,trigger将会以重复次数并发执行(或者以scheduler可以处理的近似并发数)。如果你还不熟悉DateBuilder,了解后你会发现使用它可以非常方便地构造基于开始时间(或终止时间)的调度策略。endTime属性的值会覆盖设置重复次数的属性值;比如,你可以创建一个trigger,在终止时间之前每隔10秒执行一次,你不需要去计算在开始时间和终止时间之间的重复次数,只需要设置终止时间并将重复次数设置为REPEAT_INDEFINITELY(当然,你也可以将重复次数设置为一个很大的值,并保证该值比trigger在终止时间之前实际触发的次数要大即可)。SimpleTrigger实例通过TriggerBuilder设置主要的属性,通过SimpleScheduleBuilder设置与SimpleTrigger相关的属性。要使用这些builder的静态方法,需要静态导入:
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.DateBuilder.*:
下面的例子,是基于简单调度(simple schedule)创建的trigger。建议都看一下,因为每个例子都包含一个不同的实现点:
指定时间开始触发,不重复:
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
    .withIdentity("trigger1", "group1")
    .startAt(myStartTime)                     // some Date
    .forJob("job1", "group1")                 // identify job with name, group strings
    .build();
指定时间触发,每隔10秒执行一次,重复10次:
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .startAt(myTimeToStartFiring)  // if a start time is not given (if this line were omitted), "now" is implied
    .withSchedule(simpleSchedule()
        .withIntervalInSeconds(10)
        .withRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
    .forJob(myJob) // identify job with handle to its JobDetail itself                   
    .build();
5分钟以后开始触发,仅执行一次:
trigger = (SimpleTrigger) newTrigger()
    .withIdentity("trigger5", "group1")
    .startAt(futureDate(5, IntervalUnit.MINUTE)) // use DateBuilder to create a date in the future
    .forJob(myJobKey) // identify job with its JobKey
    .build();
立即触发,每个5分钟执行一次,直到22:00:
trigger = newTrigger()
    .withIdentity("trigger7", "group1")
    .withSchedule(simpleSchedule()
        .withIntervalInMinutes(5)
        .repeatForever())
    .endAt(dateOf(22, 0, 0))
    .build();
在下一小时整点触发,每个2小时执行一次,一直重复:
trigger = newTrigger()
    .withIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
    .startAt(evenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
    .withSchedule(simpleSchedule()
        .withIntervalInHours(2)
        .repeatForever())
    // note that in this example, 'forJob(..)' is not called which is valid
    // if the trigger is passed to the scheduler along with the job  
    .build();
scheduler.scheduleJob(trigger, job);
请查阅TriggerBuilderSimpleScheduleBuilder提供的方法,以便对上述示例中未提到的选项有所了解。
TriggerBuilder(以及Quartz的其它builder)会为那些没有被显式设置的属性选择合理的默认值。比如:如果你没有调用withIdentity(..)方法,TriggerBuilder会为trigger生成一个随机的名称;如果没有调用startAt(..)方法,则默认使用当前时间,即trigger立即生效
2、SimpleTrigger Misfire策略
scheduler被停止或者线程不够用的时候,会发生出发错过misfire,SimpleTrigger有几个misfire相关的策略,告诉quartz当misfire发生的时候应该如何处理。这些策略以常量的形式在SimpleTrigger中定义(JavaDoc中介绍了它们的功能)。这些策略包括:SimpleTrigger的Misfire策略常量:
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_FIRE_NOW
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
所有的trigger都有一个Trigger.MISFIRE_INSTRUCTION_SMART_POLICY策略可以使用,该策略也是所有trigger的默认策略。如果使用smart policy,SimpleTrigger会根据实例的配置及状态,在所有MISFIRE策略中动态选择一种Misfire策略。SimpleTrigger.updateAfterMisfire()的JavaDoc中解释了该动态行为的具体细节。在使用SimpleTrigger构造trigger时,misfire策略作为基本调度(simple schedule)的一部分进行配置(通过SimpleSchedulerBuilder设置):
trigger = newTrigger()
    .withIdentity("trigger7", "group1")
    .withSchedule(simpleSchedule()
        .withIntervalInMinutes(5)
        .repeatForever()
        .withMisfireHandlingInstructionNextWithExistingCount())
    .build();

六、CronTrigger
1、如果你需要的是基于日历表示法的调度,而不是基于指定间隔的简单调度,那么CronTrigger比SimpleTrigger更合适。使用CronTrigger,你可以配置这样的调度:“每周五的中午”,或者“每个工作日的上午9:30”,或者“在一月的每个周一、周三和周五的上午9点到10点之间每隔5分钟”。与SimpleTrigger一样,CronTrigger需要设置startTime属性,表示调度生效的时间,以及(可选的)endTime属性,表示调度的结束时间。Cron表达式用于配置CronTrigger的实例,它由7个字段组成,字段之间由空格分开,它们表示的含义如下:1. 秒 (Seconds)2. 分钟 (Minutes)3. 小时 (Hours)4. 日(一个月的一天) (Day-of-Month)5. 月份    (Month)6. 周(一周的一天) (Day-of-Week)7. 年份(可选的) (Year)
一个完整的Cron表达式的例子如字符串:”0 0 12 ? * WED” - 表示“每周三的中午12:00:00”;每一个字段可以包含范围或者列举。比如,上例中的字段(即”WED“)可以被替换为:”MON-FRI”, “MON,WED,FRI”, 或者”MON-WED,SAT”。通配符()表示该字段上每一个可取的值。因此,上例中字段上的表示“每个月”。字段上的*表示“一周的每一天”。所有的字段都有一些可取的值的集合。有些就很明显 - 比如,分钟字段可以取0到59的整数,小时字段可以取0到23的整数,字段(Day-of-Month)可以取1到31的整数,不过你需要注意指定的月份到底有多少天。字段可以取0到11之间的整数,或者使用字符串表示:JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 和 DEC。字段(Days-of-Week)可以取的值为1到7(1表示Sunday),或者使用字符串表示:SUN, MON, TUE, WED, THU, FRI and SAT。字符‘/’表示增量。比如,分钟字段使用”0/15“,表示”在这个小时内,从0分钟开始,每隔15分钟“;如果分钟字段使用”3/20“,则表示”在这个小时内,从第3分钟开始,每隔20分钟“,这与在分钟字段使用“3,23,43”表示的含义是一样的。注意一个细节,“/35”的含义并不是“每隔35分钟”,而是“在这个小时内,从第0分钟开始,每隔35分钟”。字符’?’可以用于字段和字段,表示“没有具体的值“。它主要用于在这两个字段的某一个中指定某个值,更好的理解请参考下面的示例(以及CrontTrigger的JavaDoc)。字符’L’可以用于字段和字段,它是last的缩写,但是用于这两个字段时,含义并不相同。比如,“L”用于子段,表示“这个月的最后一天” - 即一月的第31天,非闰年二月的第28天。如果‘L’单独用于字段,它的含义就是“7”或者“SAT”。但是,如果‘L’用于字段时,前面还有一个值,则表示“这个月的最后一个周××” - 比如,“6L”或“FRIL”表示“这个月的最后一个周五”。我们也可以指定与这个月最后一天的偏移量,比如“L-3”表示与这个月的最后一天相差3天需要注意的是,如果使用选项‘L’,则不要使用列举和范围,否则结果将是不可预料的。字符’W’表示离某一天最近的工作日(weekday)。例如,字段上的值“15W”表示“离这个月的15号最近的工作日”。字符’#’表示“这个月的第n个周××”。例如,在字段上的“6#3”或“FRI#3”表示“这个月的3个周五”。以下为一些表达式的例子及对应的含义 - 在org.quartz.CronExpression的JavaDoc有更多的描述。Cron表达式示例:
CronTrigger示例1 - 每隔5分钟执行一次:0 0/5 * * * ?
CronTrigger示例2 - 每隔5分钟,且在该分钟的第10秒执行(如10:00:10 am, 10:05:10 am等):10 0/5 * * * ?
CronTrigger示例3 - 每周三和周五的10:30, 11:30, 12:30和13:30执行:0 30 10-13 ? * WED,FRI
Crontrigger示例4 - 在每个月的第5天和第20天,上午8点到上午10点之间每隔半小时执行,注意:该trigger不会在上午10点执行,只在上午8:00, 8:30, 9:00和9:30执行:0 0/30 8-9 5,20 * ?       
提示一下,有些调度需求太复杂了,无法使用一个trigger表达 - 比如:“在上午9点和上午10点之间,每隔5分钟执行一次,且在下午1点到下午10点之间每隔20分钟执行一次”。应对这样的需求,可以创建两个trigger,注册到同一个job上即可。
2、创建CronTrigger:
CronTrigger实例可以通过TriggerBuilder(配置主要属性)和CronScheduleBuilder(配置CronTrigger专有的属性)配置。为了以DSL风格使用这些builder,需要静态导入:
import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*:
构建一个trigger,在每天的上午8点到下午5点之间每隔2分钟执行一次,如:
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 0/2 8-17 * * ?"))
    .forJob("myJob", "group1")
    .build();
构建一个trigger,每天上午10:42执行:
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(dailyAtHourAndMinute(10, 42))
    .forJob(myJobKey)
    .build();
或者
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 42 10 * * ?"))
    .forJob(myJobKey)
    .build();
构建一个trigger,在每周三的上午10:42执行,并配置TimeZone:
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(weeklyOnDayAndHourAndMinute(DateBuilder.WEDNESDAY, 10, 42)
        .inTimeZone(TimeZone.getTimeZone("America/Los_Angeles")))
    .forJob(myJobKey)
    .build();
3、CronTriggter错过触发策略
下面的这些策略用于告诉Quartz,如果CronTrigger错过触发时应该采取的处理方式。
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_DO_NOTHING
MISFIRE_INSTRUCTION_FIRE_NOW
所有的trigger都可以使用Trigger.MISFIRE_INSTRUCTION_SMART_POLICY策略,该策略也是所有trigger的默认策略。在CronTrigger中,’smart policy’策略其实就是MISFIRE_INSTRUCTION_FIRE_NOWCronTrigger.updateAfterMisfire()的API文档中对该策略有更详细的解释。
在构造CronTrigger时,将错过触发策略作为调度的一部分进行配置(通过CronScheduleBuilder):
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 0/2 8-17 * * ?")
        .withMisfireHandlingInstructionFireAndProceed())
    .forJob("myJob", "group1")
    .build();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值