下载和安装
如果是采用maven管理依赖,则依赖配置如下:
- <dependency>
- <groupId>org.quartz-scheduler</groupId>
- <artifactId>quartz</artifactId>
- <version>2.2.3</version>
- </dependency>
- <dependency>
- <groupId>org.quartz-scheduler</groupId>
- <artifactId>quartz-jobs</artifactId>
- <version>2.2.3</version>
- </dependency>
关键接口
Scheduler
Job
- package org.quartz;
- public interface Job {
- public void execute(JobExecutionContext context)
- throws JobExecutionException;
- }
JobDetail
Trigger
SimpleTrigger很方便,如果你需要一次性执行(只是在一个给定时刻执行job),或者如果你需要一个job在一个给定的时间,并让它重复N次,并在执行之间延迟T。
CronTrigger是有用的,如果你想拥有引发基于当前日历时间表,如每个星期五,中午或在每个月的第十天 10:15。
JobBuilder
TriggerBuilder
特性
第一个quartz 程序
- import org.quartz.Job;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
- import java.util.Date;
- public class HelloJob implements Job {
- /**
- * 需要一个无参的public构造以便scheduler在它需要的时候可以实例化这个class.
- */
- public HelloJob() {
- }
- /**
- * 要执行的代码
- *
- * @param context JobExecutionContext
- * @throws JobExecutionException
- */
- public void execute(JobExecutionContext context) throws JobExecutionException {
- System.out.println("Hello World! - " + new Date());
- }
- }
- import org.quartz.DateBuilder;
- import org.quartz.JobBuilder;
- import org.quartz.JobDetail;
- import org.quartz.Scheduler;
- import org.quartz.SchedulerFactory;
- import org.quartz.Trigger;
- import org.quartz.TriggerBuilder;
- import org.quartz.impl.StdSchedulerFactory;
- import java.util.Date;
- public class SimpleExample {
- public void run() throws Exception {
- System.out.println("------- 初始化 ----------------------");
- // 首先要实例化scheduler
- SchedulerFactory schedulerFactory = new StdSchedulerFactory();
- Scheduler scheduler = schedulerFactory.getScheduler();
- System.out.println("------- 初始化完成 -----------");
- // 获取给定时间的下一个完整分钟的时间,例如给定时间 08:13:54 则会反回 08:14:00
- Date runTime = DateBuilder.evenMinuteDate(new Date());
- System.out.println("------- Job安排 -------------------");
- // 获取job实例
- JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
- // 在下一轮分钟触发运行
- Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startAt(runTime).build();
- // 告诉quartz使用某个trigger执行某个job
- scheduler.scheduleJob(job, trigger);
- System.out.println(job.getKey() + " 将会运行于: " + runTime);
- // 启动scheduler
- scheduler.start();
- System.out.println("------- 开始安排 -----------------");
- System.out.println("------- 等待65秒 -------------");
- Thread.sleep(65L * 1000L);
- // 关闭scheduler
- System.out.println("------- 关闭 ---------------------");
- scheduler.shutdown(true);
- System.out.println("------- 关闭完成 -----------------");
- }
- public static void main(String[] args) throws Exception {
- SimpleExample example = new SimpleExample();
- example.run();
- }
- }
更多关于Job and JobDetail
JobDataMap
- JobDetail job = newJob(DumbJob.class)
- .withIdentity("myJob", "group1") // name "myJob", group "group1"
- .usingJobData("jobSays", "Hello World!")
- .usingJobData("myFloatValue", 3.141f)
- .build();
- public class DumbJob implements Job {
- public DumbJob() {
- }
- public void execute(JobExecutionContext context)
- throws JobExecutionException
- {
- JobKey key = context.getJobDetail().getKey();
- JobDataMap dataMap = context.getJobDetail().getJobDataMap();
- String jobSays = dataMap.getString("jobSays");
- float myFloatValue = dataMap.getFloat("myFloatValue");
- System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
- }
- }
trigger也可以有与他们有关的JobDataMap,例如TriggerBuilder.newTrigger().usingJobData。
更多关于trigger
通用的trigger属性
优先级
注意:优先级仅仅在同一时间触发的trigger中才有效。一个在10:59触发的trigger将永远比在11:00触发的trigger先执行。
注意:当触发器被监测到需要恢复时,它的优先级将与原始的优先级相同。
触发失败说明
日历
日历必须通过addCalendar(..)方法实例化并注册到scheduler中。如果你使用HolidayCalendar,实例化之后,你应该使用它的addExcludedDate(Date date)方法将你想排除在调度器之外的日期添加进去。同一个日历实例可以被多个trigger使用,如下所示:
- HolidayCalendar cal = new HolidayCalendar();
- cal.addExcludedDate( someDate );
- cal.addExcludedDate( someOtherDate );
- sched.addCalendar("myHolidays", cal, false,false);
- Trigger t = newTrigger()
- .withIdentity("myTrigger")
- .forJob("myJob")
- .withSchedule(dailyAtHourAndMinute(9, 30)) // execute job daily at 9:30
- .modifiedByCalendar("myHolidays") // but not on holidays
- .build();
- // .. schedule job with trigger
- Trigger t2 = newTrigger()
- .withIdentity("myTrigger2")
- .forJob("myJob2")
- .withSchedule(dailyAtHourAndMinute(11, 30)) // execute job daily at 11:30
- .modifiedByCalendar("myHolidays") // but not on holidays
- .build();
- // .. schedule job with trigger2
Calendar calendar,
boolean replace,
boolean updateTriggers)
throws SchedulerException
SimpleTrigger
如果你还不熟悉Quartz的DateBuilder类,你可能发现依赖于你的开始时间(或结束时间)计算trigger的触发次数很有帮助。
- import static org.quartz.TriggerBuilder.*;
- import static org.quartz.SimpleScheduleBuilder.*;
- import static org.quartz.DateBuilder.*:
- 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,每小时开始的时候触发,每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);
SimpleTrigger有几个指令,用来通知quartz当触发失败该怎么做。这些指令被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属性可以使用,这个指定对所有的触发器类型都是可用的。
如果使用“智能策略”,SimpleTrigger会基于给定SimpleTrigger实例的配置和状态动态地选择触发的失败指令。SimpleTrigger.updateAfterMisfire()方法的Javadoc解释了这些动态行为的细节。也可以在创建SimpleTrigger时,指定失败指令作为简单scheduler的一部分。
- trigger = newTrigger()
- .withIdentity("trigger7", "group1")
- .withSchedule(simpleSchedule()
- .withIntervalInMinutes(5)
- .repeatForever()
- .withMisfireHandlingInstructionNextWithExistingCount())
- .build();
CronTrigger
如果你需要基于类似日历的观念反复触发一个job,而不是使用SimpleTrigger指定一个固定的时间间隔,相对于SimpleTrigger,CronTrigger往往更有用。
使用CronTrigger,你可以指定一个触发计划例如“每周五的中午”,或者“每个工作日上午9:00”,甚至“1月的周一,周三和周五早上9:00至10:00每五分钟”。
即便如此,和SimpleTrigger一样, CronTrigger也有一个startTime指定计划的生效时间也有一个(可选的)endTime指定计划的停止时间。
?
-
/
表达式 | 含义 |
0 0 12 * * ? | 每天12:00触发 |
0 15 10 ? * * | 每天10:15触发 |
0 15 10 * * ? | 每天10:15触发 |
0 15 10 * * ? * | 每天10:15触发 |
0 15 10 * * ? 2005 | 2005年的每天10:15触发 |
0 * 14 * * ? | 每天14:00至14:59每分钟触发 |
0 0/5 14 * * ? | 每天14:00开始至14:55每5分钟触发 |
0 0/5 14,18 * * ? | 每天14:00开始至14:55每5分钟触发,18:00开始至18:55每5分钟触发 |
0 0-5 14 * * ? | 每天14:00开始至14:05每分钟触发 |
0 10,44 14 ? 3 WED | 三月份的每个周三14:10和14:44触发 |
0 15 10 ? * MON-FRI | 每个周一至周五上午10:15触发 |
0 15 10 15 * ? | 每月15号10:15触发 |
0 15 10 L * ? | 每月最后一天10:15触发 |
0 15 10 L-2 * ? | 每月倒数第2天10:15触发 |
0 15 10 ? * 6L | 每月最后一个周五10:15触发 |
0 15 10 ? * 6L 2002-2005 | 2002年至2005年每月最后一个周五10:15触发 |
0 15 10 ? * 6#3 | 每月第3个周五10:15触发 |
0 0 12 1/5 * ? | 每月的第一天开始,每个第5天12:00触发 |
0 11 11 11 11 ? | 每年11月11号11:11触发 |
- import static org.quartz.TriggerBuilder.*;
- import static org.quartz.CronScheduleBuilder.*;
- import static org.quartz.DateBuilder.*:
- trigger = new Trigger()
- .withIdentity("trigger3", "group1")
- .withSchedule(cronSchedule("0 42 10 ? * WED"))
- .inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
- .forJob(myJobKey)
- .build();
CronTrigger失败说明
下面的说明可以在CronTrigger失败时用来介绍Quartz信息。这些介绍是CronTrigger自己定义的常量。包括:
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_DO_NOTHING
MISFIRE_INSTRUCTION_FIRE_NOW
所有的trigger都有MISFIRE_INSTRUCTION_SMART_POLICY说明可供使用,这个说明也是所有trigger类型默认的。”智能策略CronTrigger解读为“MISFIRE_INSTRUCTION_FIRE_NOW。CronTrigger.updateAfterMisfire()方法的Javadoc解析了这些行为的细节。
在构建CronTrigger时,你可以指定简单schedule的失败说明。
- trigger = newTrigger()
- .withIdentity("trigger3", "group1")
- .withSchedule(cronSchedule("0 0/2 8-17 * * ?")
- ..withMisfireHandlingInstructionFireAndProceed())
- .forJob("myJob", "group1")
- .build();
使用TriggerListener和JobListener
TriggerListener和JobListener
与trigger有关的事件包括trigger触发,trigger触发失败,trigger执行完成(trigger完成job执行完毕)。
org.quartz.TriggerListener接口
- publicinterface TriggerListener {
- public String getName();
- publicvoid triggerFired(Trigger trigger, JobExecutionContext context);
- publicboolean vetoJobExecution(Trigger trigger, JobExecutionContext context);
- publicvoid triggerMisfired(Trigger trigger);
- publicvoid triggerComplete(Trigger trigger, JobExecutionContext context, inttriggerInstructionCode);
- }
与job有关的时间包括:job即将进行的通知,和job已经完成的通知。
org.quartz.JobListener接口
- publicinterface JobListener {
- public String getName();
- publicvoid jobToBeExecuted(JobExecutionContext context);
- publicvoid jobExecutionVetoed(JobExecutionContext context);
- publicvoid jobWasExecuted(JobExecutionContext context, JobExecutionException jobException);
- }
创建你自己的监听器
要创建一个监听器,需要简单创建一个实现org.quartz.TriggerListener接口或/和org.quartz.JobListener接口的对象。然后在运行时监听器被注册到scheduler中,并且必须给定一个name(或者确切的说,它们必须能够通过它们的getName()方法给出它们的名字)。为了你的方便,而不需要实现这些接口,你的类还可以继承JobListenerSupport或TriggerListenerSupport并简单的重写你感兴趣的方法。监听器被注册到scheduler的ListenerManager 。
注意:监听器在运行时被注册到scheduler,而不是一直随job和trigger存储在JobStore中。这是因为监听器通常作为你的应用程序的一个集成点。因此,你的应用每次运行,监听器都需要重新注册进scheduler。
下面的示例演示了将感兴趣的JobListener添加进不同类型的job中。以同样的方式添加可用的TriggerListener。
添加一个感兴趣的JobListener到特定的job
scheduler.getListenerManager().addJobListener(myJobListener,KeyMatcher.jobKeyEquals(new JobKey("myJobName", "myJobGroup")));
你可能想使用静态导入导入matcher和key类,这将使你清晰的匹配matcher:
import static org.quartz.JobKey.*;
import static org.quartz.impl.matchers.KeyMatcher.*;
import static org.quartz.impl.matchers.GroupMatcher.*;
import static org.quartz.impl.matchers.AndMatcher.*;
import static org.quartz.impl.matchers.OrMatcher.*;
import static org.quartz.impl.matchers.EverythingMatcher.*;
...etc.
上面的例子将变成:
scheduler.getListenerManager().addJobListener(myJobListener,jobKeyEquals(jobKey("myJobName", "myJobGroup")));
添加一个感兴趣的JobListener到一个指定group的所有job
scheduler.getListenerManager().addJobListener(myJobListener, jobGroupEquals("myJobGroup"));
添加一个感兴趣的JobListener到两个指定的group的所有job
scheduler.getListenerManager().addJobListener(myJobListener, or(jobGroupEquals("myJobGroup"), jobGroupEquals("yourGroup")));
添加一个感兴趣的JobListener到所有job
scheduler.getListenerManager().addJobListener(myJobListener, allJobs());
使用SchedulerListener
SchedulerListener
添加一个job或trigger
移除一个trigger或job
Schduler中的一系列错误
Schduler的关闭
配置
- #============================================================================
- # Configure Main Scheduler Properties
- #============================================================================
- org.quartz.scheduler.instanceName: TestScheduler
- org.quartz.scheduler.instanceId: AUTO
- org.quartz.scheduler.skipUpdateCheck: true
- #============================================================================
- # Configure ThreadPool
- #============================================================================
- org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
- org.quartz.threadPool.threadCount: 3
- org.quartz.threadPool.threadPriority: 5
- #============================================================================
- # Configure JobStore
- #============================================================================
- org.quartz.jobStore.misfireThreshold: 60000
- org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
- #org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
- #org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
- #org.quartz.jobStore.useProperties: false
- #org.quartz.jobStore.dataSource: myDS
- #org.quartz.jobStore.tablePrefix: QRTZ_
- #org.quartz.jobStore.isClustered: false
- #============================================================================
- # Configure Datasources
- #============================================================================
- #org.quartz.dataSource.myDS.driver: org.postgresql.Driver
- #org.quartz.dataSource.myDS.URL: jdbc:postgresql://localhost/dev
- #org.quartz.dataSource.myDS.user: jhouse
- #org.quartz.dataSource.myDS.password:
- #org.quartz.dataSource.myDS.maxConnections: 5
- #============================================================================
- # Configure Plugins
- #============================================================================
- org.quartz.plugin.triggHistory.class: org.quartz.plugins.history.LoggingJobHistoryPlugin
- org.quartz.plugin.jobInitializer.class: org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
- org.quartz.plugin.jobInitializer.fileNames: quartz_data.xml
- org.quartz.plugin.jobInitializer.failOnFileNotFound: true
- org.quartz.plugin.jobInitializer.scanInterval: 120
- org.quartz.plugin.jobInitializer.wrapInUserTransaction: false