概述
SimpleTrigger 可以让你在某个精确的时间执行一次 Job,或者在某个精确的时间执行之后在特定的时间间隔内重复执行。
例如,如果你想在 2015 年 1 月 13 日上午 11:23:54 时间点精确执行,或者在这个时间点执行完成后再执行 5 次,每次间隔 10 秒钟。
从SimpleTrigger接口的实现类SimpleTriggerImpl的源码中我们可以看到如下属性:
开始时间、结束时间、重复次数、重复间隔时间等,这些属性看起来都很直观,其中只有结束时间需要花点时间来特殊说明一下。
- 重复次数可以是 0,正整数(int),或者是SimpleTrigger.REPEAT_INDEFINITELY 常量值。
- 重复间隔时间必须是 0 或者正长整数(long),并且单位是毫秒。注意,如果将重复间隔时间设置为0,可能会发生 Trigger 同时触发(并发)的问题。
如果熟悉Quartz 的DateBuilder类 ,你可能会发现使用它基于开始时间(或结束时间)来计算触发次数非常有用。结束时间属性将覆盖重复次数属性。
这在某些情况下非常有用,例如当你在创建好一个 Trigger 后,设置在指定的时间内每 10 秒执行一次,如果设置了结束时间就不用去计算开始时间到结束时间之间到底需要执行多少次,你可以简单的设置结束时间,并使用 REPEAT_INDEFINITELY 作为重复次数(你还可以简单地写一个足够大的数字作为重复次数,只要这个数字大于在结束时间之前的实际执行次数即可)。
SimpleTrigger 实例可以使用 TriggerBuilder(基于 Trigger 的主要属性) 或 SimpleScheduleBuilder (基于 SimpleTrigger 的特殊属性) 创建。要使用 DSL 风格需要先进行静态导入:
import static org.quartz.TriggerBuilder.*; import static org.quartz.SimpleScheduleBuilder.*; import static org.quartz.DateBuilder.*:
小例子
我们来看几个小例子:
创建一个在某个时间点执行的 Trigger:
SimpleTrigger trigger = (SimpleTrigger) newTrigger() .withIdentity("trigger1", "group1") .startAt(myStartTime) // some Date .forJob("job1", "group1") // identify job with name, group strings .build();
创建一个在某个时间点执行的 Trigger,并且随后每 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();
创建一个 Trigger,并且在 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();
创建一个 Trigger,并且立即执行一次,以后每 5 分钟执行一次,直到 22:00
trigger = newTrigger() .withIdentity("trigger7", "group1") .withSchedule(simpleSchedule() .withIntervalInMinutes(5) .repeatForever()) .endAt(dateOf(22, 0, 0)) .build();
创建一个 Trigger,并且在下一小时开始的时候执行一次,以后每两小时执行一次,永久循环
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);
花点时间研究所有 TriggerBuilder 和 SimpleScheduleBuilder 中的方法,你将更加熟悉如何使用,这些方法有很多都没有在上面的例子中出现。
注意,TriggerBuilder(或者 Quartz 的其它 Builder)在你没有显式的设置属性的时候会设置一个合理的默认属性。例如,如果你没有调用 withIdentity(…) 方法,那么 TriggerBuilder 将会为你的 Trigger 设置一个默认名称;如果没有调用 startAt(…) 方法,那么当前时间将会作为开始时间。
SimpleTrigger 的错过触发机制
当 Quartz 发生错过触发事件后,SimpleTrigger 提供了几个机制,这些机制以常量形式保存在 SimpleTrigger 中.
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.MISFIRE_INSTRUCTION_SMART_POLICY (智能策略)是所有 Trigger 的默认值。
当创建 SimpleTrigger 的时候,可以通过 SimpleSchedulerBuilder 指定错过触发机制:
trigger = newTrigger() .withIdentity("trigger7", "group1") .withSchedule(simpleSchedule() .withIntervalInMinutes(5) .repeatForever() .withMisfireHandlingInstructionNextWithExistingCount()) .build();
示例
package com.xgj.quartz.quartzItself.simpleTriggerDemo; import java.util.Date; import org.apache.log4j.Logger; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey; public class SimpleJob implements Job { private static Logger _log = Logger.getLogger(SimpleJob.class); /** * Empty constructor for job initialization */ public SimpleJob() { } /** * <p> * Called by the <code>{@link org.quartz.Scheduler}</code> when a * <code>{@link org.quartz.Trigger}</code> fires that is associated with the * <code>Job</code>. * </p> * * @throws JobExecutionException * if there is an exception while executing the job. */ public void execute(JobExecutionContext context) throws JobExecutionException { // This job simply prints out its job name and the // date and time that it is running JobKey jobKey = context.getJobDetail().getKey(); _log.info("SimpleJob says: " + jobKey + " executing at " + new Date()); } }
package com.xgj.quartz.quartzItself.simpleTriggerDemo; import static org.quartz.DateBuilder.futureDate; import static org.quartz.JobBuilder.newJob; import static org.quartz.JobKey.jobKey; import static org.quartz.SimpleScheduleBuilder.simpleSchedule; import static org.quartz.TriggerBuilder.newTrigger; import java.util.Date; import org.apache.log4j.Logger; import org.quartz.DateBuilder; import org.quartz.DateBuilder.IntervalUnit; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerFactory; import org.quartz.SchedulerMetaData; import org.quartz.SimpleTrigger; import org.quartz.impl.StdSchedulerFactory; import com.xgj.quartz.quartzItself.quickDemo.SimpleJob; /** * * * @ClassName: SimpleTriggerExample * * @Description: This Example will demonstrate all of the basics of scheduling * capabilities of Quartz using Simple Triggers. * * @author: Mr.Yang * * @date: 2017年10月7日 下午8:49:43 */ public class SimpleTriggerExample { public void run() throws Exception { Logger log = Logger.getLogger(SimpleTriggerExample.class); log.info("------- Initializing -------------------"); // First we must get a reference to a scheduler SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); log.info("------- Initialization Complete --------"); log.info("------- Scheduling Jobs ----------------"); // jobs can be scheduled before sched.start() has been called // get a "nice round" time a few seconds in the future... Date startTime = DateBuilder.nextGivenSecondDate(null, 15); // job1 will only fire once at date/time "ts" JobDetail job = newJob(SimpleJob.class).withIdentity("job1", "group1") .build(); SimpleTrigger trigger = (SimpleTrigger) newTrigger() .withIdentity("trigger1", "group1").startAt(startTime).build(); // schedule it to run! Date ft = sched.scheduleJob(job, trigger); log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds"); // job2 will only fire once at date/time "ts" job = newJob(SimpleJob.class).withIdentity("job2", "group1").build(); trigger = (SimpleTrigger) newTrigger() .withIdentity("trigger2", "group1").startAt(startTime).build(); ft = sched.scheduleJob(job, trigger); log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds"); // job3 will run 11 times (run once and repeat 10 more times) // job3 will repeat every 10 seconds job = newJob(SimpleJob.class).withIdentity("job3", "group1").build(); trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(startTime) .withSchedule( simpleSchedule().withIntervalInSeconds(10) .withRepeatCount(10)).build(); ft = sched.scheduleJob(job, trigger); log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds"); // the same job (job3) will be scheduled by a another trigger // this time will only repeat twice at a 70 second interval trigger = newTrigger() .withIdentity("trigger3", "group2") .startAt(startTime) .withSchedule( simpleSchedule().withIntervalInSeconds(10) .withRepeatCount(2)).forJob(job).build(); ft = sched.scheduleJob(trigger); log.info(job.getKey() + " will [also] run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds"); // job4 will run 6 times (run once and repeat 5 more times) // job4 will repeat every 10 seconds job = newJob(SimpleJob.class).withIdentity("job4", "group1").build(); trigger = newTrigger() .withIdentity("trigger4", "group1") .startAt(startTime) .withSchedule( simpleSchedule().withIntervalInSeconds(10) .withRepeatCount(5)).build(); ft = sched.scheduleJob(job, trigger); log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds"); // job5 will run once, five minutes in the future job = newJob(SimpleJob.class).withIdentity("job5", "group1").build(); trigger = (SimpleTrigger) newTrigger() .withIdentity("trigger5", "group1") .startAt(futureDate(5, IntervalUnit.MINUTE)).build(); ft = sched.scheduleJob(job, trigger); log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds"); // job6 will run indefinitely, every 40 seconds job = newJob(SimpleJob.class).withIdentity("job6", "group1").build(); trigger = newTrigger() .withIdentity("trigger6", "group1") .startAt(startTime) .withSchedule( simpleSchedule().withIntervalInSeconds(40) .repeatForever()).build(); ft = sched.scheduleJob(job, trigger); log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds"); log.info("------- Starting Scheduler ----------------"); // All of the jobs have been added to the scheduler, but none of the // jobs // will run until the scheduler has been started sched.start(); log.info("------- Started Scheduler -----------------"); // jobs can also be scheduled after start() has been called... // job7 will repeat 20 times, repeat every five minutes job = newJob(SimpleJob.class).withIdentity("job7", "group1").build(); trigger = newTrigger() .withIdentity("trigger7", "group1") .startAt(startTime) .withSchedule( simpleSchedule().withIntervalInMinutes(5) .withRepeatCount(20)).build(); ft = sched.scheduleJob(job, trigger); log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds"); // jobs can be fired directly... (rather than waiting for a trigger) job = newJob(SimpleJob.class).withIdentity("job8", "group1") .storeDurably().build(); sched.addJob(job, true); log.info("'Manually' triggering job8..."); sched.triggerJob(jobKey("job8", "group1")); log.info("------- Waiting 30 seconds... --------------"); try { // wait 33 seconds to show jobs Thread.sleep(30L * 1000L); // executing... } catch (Exception e) { // } // jobs can be re-scheduled... // job 7 will run immediately and repeat 10 times for every second log.info("------- Rescheduling... --------------------"); trigger = newTrigger() .withIdentity("trigger7", "group1") .startAt(startTime) .withSchedule( simpleSchedule().withIntervalInMinutes(5) .withRepeatCount(20)).build(); ft = sched.rescheduleJob(trigger.getKey(), trigger); log.info("job7 rescheduled to run at: " + ft); log.info("------- Waiting five minutes... ------------"); try { // wait five minutes to show jobs Thread.sleep(300L * 1000L); // executing... } catch (Exception e) { // } log.info("------- Shutting Down ---------------------"); sched.shutdown(true); log.info("------- Shutdown Complete -----------------"); // display some stats about the schedule that just ran SchedulerMetaData metaData = sched.getMetaData(); log.info("Executed " + metaData.getNumberOfJobsExecuted() + " jobs."); } public static void main(String[] args) throws Exception { SimpleTriggerExample example = new SimpleTriggerExample(); example.run(); } }
示例源码
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster