CronTrigger配置格式:html
格式: [秒] [分] [小时] [日] [月] [周] [年]java
序号 | 说明 | 是否必填 | 容许填写的值 | 容许的通配符 |
---|---|---|---|---|
1 | 秒 | 是 | 0-59 | , - * / |
2 | 分 | 是 | 0-59 | , - * / |
3 | 小时 | 是 | 0-23 | , - * / |
4 | 日 | 是 | 1-31 | , - * ? / L W |
5 | 月 | 是 | 1-12 or JAN-DEC | , - * / |
6 | 周 | 是 | 1-7 or SUN-SAT | , - * ? / L # |
7 | 年 | 否 | empty 或 1970-2099 | , - * / |
通配符说明:服务器
* 表示全部值. 例如:在分的字段上设置 "*",表示每一分钟都会触发。并发
? 表示不指定值。使用的场景为不须要关心当前设置这个字段的值。例如:要在每个月的10号触发一个操做,但不关心是周几,因此须要周位置的那个字段设置为"?" 具体设置为 0 0 0 10 * ?框架
- 表示区间。例如 在小时上设置 "10-12",表示 10,11,12点都会触发。ide
, 表示指定多个值,例如在周字段上设置 "MON,WED,FRI" 表示周一,周三和周五触发学习
/ 用于递增触发。如在秒上面设置"5/15" 表示从5秒开始,每增15秒触发(5,20,35,50)。 在月字段上设置'1/3'所示每个月1号开始,每隔三天触发一次。测试
L 表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,若是是二月还会依据是不是润年[leap]), 在周字段上表示星期六,至关于"7"或"SAT"。若是在"L"前加上数字,则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表示“本月最后一个星期五" ui
W 表示离指定日期的最近那个工做日(周一至周五). 例如在日字段上设置"15W",表示离每个月15号最近的那个工做日触发。若是15号正好是周六,则找最近的周五(14号)触发, 若是15号是周未,则找最近的下周一(16号)触发.若是15号正好在工做日(周一至周五),则就在该天触发。若是指定格式为 "1W",它则表示每个月1号日后最近的工做日触发。若是1号正是周六,则将在3号下周一触发。(注,"W"前只能设置具体的数字,不容许区间"-").this
# 序号(表示每个月的第几个周几),例如在周字段上设置"6#3"表示在每个月的第三个周六.注意若是指定"#5",正好第五周没有周六,则不会触发该配置(用在母亲节和父亲节再合适不过了)
<br/>
@DisallowConcurrentExecution (简单来讲:不容许任务还没结束,新开线程执行任务)
此标记用在实现Job的类上面,意思是不容许并发执行,按照我以前的理解是 不容许调度框架在同一时刻调用Job类,后来通过测试发现并非这样,而是Job(任务)的执行时间[好比须要10秒]大于任务的时间间隔[Interval(5秒)],那么默认状况下,调度框架为了能让 任务按照咱们预约的时间间隔执行,会立刻启用新的线程执行任务。不然的话会等待任务执行完毕之后 再从新执行!(这样会致使任务的执行不是按照咱们预先定义的时间间隔执行)
测试代码,这是官方提供的例子。设定的时间间隔为3秒,但job执行时间是5秒,设置@DisallowConcurrentExecution之后程序会等任务执行完毕之后再去执行,不然会在3秒时再启用新的线程执行
org.quartz.threadPool.threadCount = 5 这里配置框架的线程池中线程的数量,要多配置几个,不然@DisallowConcurrentExecution不起做用
org.quartz.scheduler.instanceName = MyScheduler org.quartz.threadPool.threadCount = 5 org.quartz.jobStore.class =org.quartz.simpl.RAMJobStore
@PersistJobDataAfterExecution @DisallowConcurrentExecution public class StatefulDumbJob implements Job { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Constants. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ public static final String NUM_EXECUTIONS = "NumExecutions"; public static final String EXECUTION_DELAY = "ExecutionDelay"; /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Constructors. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ public StatefulDumbJob() { } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Interface. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** * <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 { System.err.println("---" + context.getJobDetail().getKey() + " executing.[" + new Date() + "]"); JobDataMap map = context.getJobDetail().getJobDataMap(); int executeCount = 0; if (map.containsKey(NUM_EXECUTIONS)) { executeCount = map.getInt(NUM_EXECUTIONS); } executeCount++; map.put(NUM_EXECUTIONS, executeCount); long delay = 5000l; if (map.containsKey(EXECUTION_DELAY)) { delay = map.getLong(EXECUTION_DELAY); } try { Thread.sleep(delay); } catch (Exception ignore) { } System.err.println(" -" + context.getJobDetail().getKey() + " complete (" + executeCount + ")."); } }
public class MisfireExample { public void run() throws Exception { Logger log = LoggerFactory.getLogger(MisfireExample.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 start() has been called // get a "nice round" time a few seconds in the future... Date startTime = nextGivenSecondDate(null, 15); // statefulJob1 will run every three seconds // (but it will delay for ten seconds) JobDetail job = newJob(StatefulDumbJob.class) .withIdentity("statefulJob1", "group1") .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L) .build(); SimpleTrigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startAt(startTime) .withSchedule(simpleSchedule() .withIntervalInSeconds(3) .repeatForever()) .build(); Date 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 ----------------"); // jobs don't start firing until start() has been called... sched.start(); log.info("------- Started Scheduler -----------------"); try { // sleep for ten minutes for triggers to file.... Thread.sleep(600L * 1000L); } catch (Exception e) { } log.info("------- Shutting Down ---------------------"); sched.shutdown(true); log.info("------- Shutdown Complete -----------------"); SchedulerMetaData metaData = sched.getMetaData(); log.info("Executed " + metaData.getNumberOfJobsExecuted() + " jobs."); } public static void main(String[] args) throws Exception { MisfireExample example = new MisfireExample(); example.run(); } }
@PersistJobDataAfterExecution
此标记说明在执行完Job的execution方法后保存JobDataMap当中固定数据,在默认状况下 也就是没有设置 @PersistJobDataAfterExecution的时候 每一个job都拥有独立JobDataMap
不然改任务在重复执行的时候具备相同的JobDataMap
@PersistJobDataAfterExecution @DisallowConcurrentExecution public class BadJob1 implements Job { public BadJob1() { } public void execute(JobExecutionContext context) throws JobExecutionException { JobKey jobKey = context.getJobDetail().getKey(); JobDataMap dataMap = context.getJobDetail().getJobDataMap(); int denominator = dataMap.getInt("denominator"); System.out.println("---" + jobKey + " executing at " + new Date() + " with denominator " + denominator); denominator++; dataMap.put("denominator", denominator); } }
public class JobExceptionExample { public void run() throws Exception { // First we must get a reference to a scheduler SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); // jobs can be scheduled before start() has been called // get a "nice round" time a few seconds in the future... Date startTime = nextGivenSecondDate(null, 2); JobDetail job = newJob(BadJob1.class) .withIdentity("badJob1", "group1") .usingJobData("denominator", "0") .build(); SimpleTrigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startAt(startTime) .withSchedule(simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); Date ft = sched.scheduleJob(job, trigger); //任务每2秒执行一次 那么在BadJob1的方法中拿到的JobDataMap的数据是共享的. //这里要注意一个状况: 就是JobDataMap的数据共享只针对一个BadJob1任务。 //若是在下面在新增长一个任务 那么他们之间是不共享的 好比下面 JobDetail job2 = newJob(BadJob1.class) .withIdentity("badJob1", "group1") .usingJobData("denominator", "0") .build(); SimpleTrigger trigger2 = newTrigger() .withIdentity("trigger1", "group1") .startAt(startTime) .withSchedule(simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); //这个job2与job执行的JobDataMap不共享 sched.scheduleJob(job2, trigger2); sched.start(); try { // sleep for 30 seconds Thread.sleep(30L * 1000L); } catch (Exception e) { } sched.shutdown(false); } public static void main(String[] args) throws Exception { JobExceptionExample example = new JobExceptionExample(); example.run(); } }
requestRecovery的意思是当任务在执行过程当中出现意外 好比服务器down了 那么在重启时候是否恢复任务
JobDetail job = newJob(HelloJob.class) .withIdentity("job1", "group1") .storeDurably() .requestRecovery() .build();
<br/>
问题1 若是任务执行发生错误了怎么办!
Quartz提供了二种解决方法:
问题2 怎么去执行呢?
Quartz的解决方式是:在你的程序出错时,用Quartz提供的JobExecutionException类相关方法很好的解决
1、当即从新执行该任务
当任务中出现异常时,咱们捕获它,而后转换为JobExecutionExceptions异常抛出,同时能够控制调度引擎当即从新执行这个任务。
try { int zero = 0; int calculation = 4815 / zero; } catch (Exception e) { _log.info("--- Error in job!"); JobExecutionException e2 = new JobExecutionException(e); // this job will refire immediately e2.refireImmediately(); throw e2; }
2、取消全部与这个任务关联的触发器
try { int zero = 0; int calculation = 4815 / zero; } catch (Exception e) { _log.info("--- Error in job!"); JobExecutionException e2 = new JobExecutionException(e); // Quartz will automatically unschedule // all triggers associated with this job // so that it does not run again e2.setUnscheduleAllTriggers(true); throw e2; }
<br/>
https://www.cnblogs.com/daxin...
经常使用操做代码:
http://www.quartz-scheduler.o...
<br/>
Job:
public class PrintPropsJob implements Job { public PrintPropsJob() { // Instances of Job must have a public no-argument constructor. } public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap data = context.getMergedJobDataMap(); System.out.println("someProp = " + data.getString("someProp")); } }
Define job instance:
JobDetail job1 = newJob(MyJobClass.class) .withIdentity("job1", "group1") //标识任务 .usingJobData("someProp", "someValue") //input data .build();
<br/>
// Define job instance JobDetail job1 = newJob(ColorJob.class) .withIdentity("job1", "group1") .build(); // Define a Trigger that will fire "now", and not repeat Trigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startNow() .build(); // Schedule the job with the trigger sched.scheduleJob(job, trigger);
<br/>
// Add the new job to the scheduler, instructing it to "replace" // the existing job with the given name and group (if any) JobDetail job1 = newJob(MyJobClass.class) .withIdentity("job1", "group1") .build(); // store, and set overwrite flag to 'true' scheduler.addJob(job1, true);
<br/>
有一些业务场景,咱们须要手动去更新任务的触发时间,好比某个任务是每隔10分钟触发一次,如今须要改为每隔20分钟触发一次,这样既就须要手动的更新触发器
官方的例子:
http://www.quartz-scheduler.o...
Replacing a trigger 替换触发器,经过triggerkey移除旧的触发器,同时添加一个新的进去。
// Define a new Trigger Trigger trigger = newTrigger() .withIdentity("newTrigger", "group1") .startNow() .build(); // tell the scheduler to remove the old trigger with the given key, and put the new one in its place sched.rescheduleJob(triggerKey("oldTrigger", "group1"), trigger);
可是有一个地方须要注意:sched.rescheduleJob(triggerKey("oldTrigger", "group1"), trigger); 这个方法返回一个Date.
若是返回 null 说明替换失败,缘由就是旧触发器没有找到,因此新的触发器也不会设置进去.
<br/>
Quartz Scheduler 能够对Job(任务)创建一个监听器,分别对任务执行 以前-以后-取消 3个状态进行监听。
实现监听器须要实现JobListener接口,而后注册到Scheduler上就能够了。
一:首先写一个监听器实现类
package com.gary.operation.jobdemo.example1; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobListener; public class MyJobListener implements JobListener { @Override public String getName() { return "MyJobListener"; } /** * (1) * 任务执行以前执行 * Called by the Scheduler when a JobDetail is about to be executed (an associated Trigger has occurred). */ @Override public void jobToBeExecuted(JobExecutionContext context) { System.out.println("MyJobListener.jobToBeExecuted()"); } /** * (2) * 这个方法正常状况下不执行,可是若是当TriggerListener中的vetoJobExecution方法返回true时,那么执行这个方法. * 须要注意的是 若是方法(2)执行 那么(1),(3)这个俩个方法不会执行,由于任务被终止了嘛. * Called by the Scheduler when a JobDetail was about to be executed (an associated Trigger has occurred), * but a TriggerListener vetoed it's execution. */ @Override public void jobExecutionVetoed(JobExecutionContext context) { System.out.println("MyJobListener.jobExecutionVetoed()"); } /** * (3) * 任务执行完成后执行,jobException若是它不为空则说明任务在执行过程当中出现了异常 * Called by the Scheduler after a JobDetail has been executed, and be for the associated Trigger's triggered(xx) method has been called. */ @Override public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { System.out.println("MyJobListener.jobWasExecuted()"); } }
二:将这个监听器注册到Scheduler
假设有一个任务的key是 job1与 group1
// define the job and tie it to our HelloJob class JobDetail job = newJob(HelloJob.class) .withIdentity("job1", "group1") .build();
全局注册,全部Job都会起做用 Registering A JobListener With The Scheduler To Listen To All Jobs sched.getListenerManager().addJobListener(new MyJobListener());
指定具体的任务 Registering A JobListener With The Scheduler To Listen To A Specific Job Matcher<JobKey> matcher = KeyMatcher.keyEquals(new JobKey("job1", "group1")); sched.getListenerManager().addJobListener(new MyJobListener(), matcher);
指定一组任务 Registering A JobListener With The Scheduler To Listen To All Jobs In a Group GroupMatcher<JobKey> matcher = GroupMatcher.jobGroupEquals("group1"); sched.getListenerManager().addJobListener(new MyJobListener(), matcher);
能够根据组的名字匹配开头和结尾或包含 GroupMatcher<JobKey> matcher = GroupMatcher.groupStartsWith("g"); GroupMatcher<JobKey> matcher = GroupMatcher.groupContains("g"); sched.getListenerManager().addJobListener(new MyJobListener(), matcher);
<br/>
Using CronTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(dailyAtHourAndMinute(15, 0)) // fire every day at 15:00 .build();
Using SimpleTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(tomorrowAt(15, 0, 0) // first fire time 15:00:00 tomorrow .withSchedule(simpleSchedule() .withIntervalInHours(24) // interval is actually set at 24 hours' worth of milliseconds .repeatForever()) .build();
Using CalendarIntervalTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(tomorrowAt(15, 0, 0) // 15:00:00 tomorrow .withSchedule(calendarIntervalSchedule() .withIntervalInDays(1)) // interval is set in calendar days .build();
<br/>
当多个触发器在一个相同的时间内触发,而且调度引擎中的资源有限的状况下,那么具备较高优先级的触发器先触发。
须要将配置文件中的org.quartz.threadPool.threadCount = 1设置为1,这样能更好的测试出效果。
package com.gary.operation.jobdemo.example14; import static org.quartz.DateBuilder.futureDate; import static org.quartz.JobBuilder.newJob; import static org.quartz.SimpleScheduleBuilder.simpleSchedule; import static org.quartz.TriggerBuilder.newTrigger; import java.util.Date; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerFactory; import org.quartz.Trigger; import org.quartz.DateBuilder.IntervalUnit; import org.quartz.impl.StdSchedulerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PriorityExample { public void run() throws Exception { Logger log = LoggerFactory.getLogger(PriorityExample.class); // First we must get a reference to a scheduler SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); JobDetail job = newJob(TriggerEchoJob.class) .withIdentity("TriggerEchoJob") .build(); Date startTime = futureDate(5, IntervalUnit.SECOND); Trigger trigger1 = newTrigger() .withIdentity("Priority7 Trigger5SecondRepeat") .startAt(startTime) .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5)) .withPriority(7) .forJob(job) .build(); Trigger trigger2 = newTrigger() .withIdentity("Priority5 Trigger10SecondRepeat") .startAt(startTime) .withPriority(5) .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5)) .forJob(job) .build(); Trigger trigger3 = newTrigger() .withIdentity("Priority10 Trigger15SecondRepeat") .startAt(startTime) .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5)) .withPriority(10) .forJob(job) .build(); // Tell quartz to schedule the job using our trigger sched.scheduleJob(job, trigger1); sched.scheduleJob(trigger2); sched.scheduleJob(trigger3); sched.start(); log.info("------- Waiting 30 seconds... -------------"); try { Thread.sleep(30L * 1000L); // executing... } catch (Exception e) { } sched.shutdown(true); } public static void main(String[] args) throws Exception { PriorityExample example = new PriorityExample(); example.run(); } }
(笔记内容大部分来源: https://www.cnblogs.com/daxin...