Quartz Cookbook是Quartz的一些简洁的代码示例,用于做特殊的事情。
目录:
这些示例假定您已经使用Quartz的DSL类的静态导入,例如:
import static org.quartz.JobBuilder.*; import static org.quartz.TriggerBuilder.*; import static org.quartz.SimpleScheduleBuilder.*; import static org.quartz.CronScheduleBuilder.*; import static org.quartz.CalendarIntervalScheduleBuilder.*; import static org.quartz.JobKey.*; import static org.quartz.TriggerKey.*; import static org.quartz.DateBuilder.*; 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.*;
参考地址:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/cookbook/
1、实例化调度器
实例化默认调度器
// “默认”调度程序在当前工作目录中的“quartz.properties”中定义,在类路径中定义,或者在quartz.jar中默认定义 SchedulerFactory sf = new StdSchedulerFactory(); Scheduler scheduler = sf.getScheduler(); // 调度程序在启动之前不会执行任务(尽管可以在start()之前进行调度) scheduler.start();
从特定属性实例化特定的调度程序
StdSchedulerFactory sf = new StdSchedulerFactory(); sf.initialize(schedulerProperties); Scheduler scheduler = sf.getScheduler(); scheduler.start();
从特定属性文件中实例化特定调度程序
StdSchedulerFactory sf = new StdSchedulerFactory(); sf.initialize(fileName); Scheduler scheduler = sf.getScheduler(); scheduler.start();
2、将计划程序置于待机模式
// start() was previously invoked on the scheduler scheduler.standby(); // 现在调度程序将不会触发/执行job // ... scheduler.start(); // 现在调度程序将触发并执行job
3、关闭计划程序
要关闭/销毁调度程序,只需调用shutdown(..)方法之一。
关闭调度程序后,无法重新启动(因为线程和其他资源被永久销毁)。 如果您想简单地暂停调度程序一段时间,请参阅suspend方法。
等待执行作业完成
//shutdown() 在执行作业完成执行之前不返回 scheduler.shutdown(true);
不要等待执行作业完成
//shutdown() 立即返回,但执行作业继续运行到完成 scheduler.shutdown(); //或者 scheduler.shutdown(false);
If you are using the org.quartz.ee.servlet.QuartzInitializerListener
to fire up a scheduler in your servlet container, its contextDestroyed()
method will shutdown the scheduler when your application is undeployed or the application server shuts down (unless its shutdown-on-unload property has been explicitly set to false).
如果您正在使用org.quartz.ee.servlet.QuartzInitializerListener来启动servlet容器中的调度程序,那么当您的应用程序取消部署或应用程序服务器关闭时,其contextDestroyed()方法将关闭调度程序(除非其shutdown-on-unload属性已被明确设置为false)
4、在Servlet容器内初始化调度程序
有两种方法,如下所示。
对于这两种情况,请确保查看相关类的JavaDOC以查看所有可能的配置参数,因为下面并非完整示例。
添加Context/Container Listene 到 web.xml
... <context-param> <param-name>quartz:config-file</param-name> <param-value>/some/path/my_quartz.properties</param-value> </context-param> <context-param> <param-name>quartz:shutdown-on-unload</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>quartz:wait-on-shutdown</param-name> <param-value>false</param-value> </context-param> <context-param> <param-name>quartz:start-scheduler-on-load</param-name> <param-value>true</param-value> </context-param> ... <listener> <listener-class> org.quartz.ee.servlet.QuartzInitializerListener </listener-class> </listener> ...
将启动Servlet添加到web.xml
... <servlet> <servlet-name>QuartzInitializer</servlet-name> <servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class> <init-param> <param-name>shutdown-on-unload</param-name> <param-value>true</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> ...
5、利用多个(非群集)调度器实例
看原文:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/cookbook/MultipleSchedulers.html
6、定义一个Job(包含输入数据)
job.class
public class PrintPropsJob implements Job { public PrintPropsJob() { // Job的实例必须有一个public的无参数构造函数。 } public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap data = context.getMergedJobDataMap(); System.out.println("someProp = " + data.getString("someProp")); } }
定义job实例
// Define job instance JobDetail job1 = newJob(MyJobClass.class) .withIdentity("job1", "group1") .usingJobData("someProp", "someValue") .build();
另请注意,如果您的Job类包含与您的JobDataMap键匹配的setter方法(例如上述示例中的数据为“setSomeProp”),并且您使用默认的JobFactory实现,则Quartz将使用JobDataMap值自动调用setter方法, 并且没有必要在Job的执行方法中具有从JobDataMap中检索值的代码。
7、Scheduling job
// 定义job实例 JobDetail job1 = newJob(ColorJob.class) .withIdentity("job1", "group1") .build(); // 定义一个触发器,立即触发,不重复 Trigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startNow() .build(); // 安排与触发任务 sched.scheduleJob(job, trigger);
8、Unscheduling Job
Unscheduling特定触发器的job
// 从job中取消特定的触发器(一个job可能有多个触发器) scheduler.unscheduleJob(triggerKey("trigger1", "group1"));
删除一个job并且Unscheduling所有相关此job的触发器
// Schedule the job with the trigger scheduler.deleteJob(jobKey("job1", "group1"));
9、存储 job 任务
Storing(存储) a Job
// 定义持久的作业实例(持久作业可以不存在触发器) JobDetail job1 = newJob(MyJobClass.class) .withIdentity("job1", "group1") .storeDurably() .build(); // 将job添加到调度程序去存储 sched.addJob(job, false);
10、调度一个已经存储过的 Job 任务
// Define a Trigger that will fire "now" and associate it with the existing job Trigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startNow() .forJob(jobKey("job1", "group1")) .build(); // 调度关联触发器 sched.scheduleJob(trigger);
11、更新已有 Job 任务
// 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, 设置覆盖flag为 'true' scheduler.addJob(job1, true);
12、更新已有 Tragger 触发器
替换触发器
// 定义一个新的触发器 Trigger trigger = newTrigger() .withIdentity("newTrigger", "group1") .startNow() .build(); // 告诉调度程序使用给定的键删除旧的触发器,并将新的触发器放在其位置 sched.rescheduleJob(triggerKey("oldTrigger", "group1"), trigger);
更新已有触发器
// 检索触发器 Trigger oldTrigger = sched.getTrigger(triggerKey("oldTrigger", "group1"); // 获取产生触发器的构建器 TriggerBuilder tb = oldTrigger.getTriggerBuilder(); // 更新与构建器关联的计划,并构建新的触发器(可以调用其他构建器方法,以任何所需的方式更改触发器) Trigger newTrigger = tb.withSchedule(simpleSchedule() .withIntervalInSeconds(10) .withRepeatCount(10) .build(); sched.rescheduleJob(oldTrigger.getKey(), newTrigger);
13、使用XML文件中定义的Job和Trigger初始化调度程序
您可以使用XMLSchedulingDataProcessorPlugin(其中1.8版本替换旧的JobInitializationPlugin)来初始化具有预定义作业和触发器的调度程序。 在示例/ example10中的Quartz分布中提供了一个示例。 但是,以下是插件的简单描述。
首先,我们需要在调度器属性中明确指定我们要使用XMLSchedulingDataProcessorPlugin。 这是一个例子的摘录quartz.properties:
#=================================================== # Configure the Job Initialization Plugin #=================================================== org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin org.quartz.plugin.jobInitializer.fileNames = jobs.xml org.quartz.plugin.jobInitializer.failOnFileNotFound = true org.quartz.plugin.jobInitializer.scanInterval = 10 org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
让我们看看每个属性的作用:
-
fileNames:逗号分隔的文件名列表(带路径)。 这些文件包含作业和关联触发器的xml定义。 稍后我们将看到一个示例jobs.xml定义。
-
failOnFileNotFound:如果没有找到xml定义文件,插件是否会引发异常,从而防止自身(插件)初始化?
-
scanInterval:如果检测到文件更改,则可以重新加载xml定义文件。 这是文件查看的时间间隔(以秒为单位)。 设置为0以禁用扫描。
-
wrapInUserTransaction:如果使用JobStoreCMT的XMLSchedulingDataProcessorPlugin,请确保将此属性的值设置为true,否则可能会遇到意外行为。
jobs.xml文件(或在fileNames属性中为其使用的任何其他名称)声明性地定义作业和触发器。 它还可以包含删除现有数据的指令。 这是一个不言自明的例子:
<?xml version='1.0' encoding='utf-8'?> <job-scheduling-data xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd" version="1.8"> <schedule> <job> <name>my-very-clever-job</name> <group>MYJOB_GROUP</group> <description>The job description</description> <job-class>com.acme.scheduler.job.CleverJob</job-class> <job-data-map allows-transient-data="false"> <entry> <key>burger-type</key> <value>hotdog</value> </entry> <entry> <key>dressing-list</key> <value>ketchup,mayo</value> </entry> </job-data-map> </job> <trigger> <cron> <name>my-trigger</name> <group>MYTRIGGER_GROUP</group> <job-name>my-very-clever-job</job-name> <job-group>MYJOB_GROUP</job-group> <!-- trigger every night at 4:30 am --> <!-- do not forget to light the kitchen's light --> <cron-expression>0 30 4 * * ?</cron-expression> </cron> </trigger> </schedule> </job-scheduling-data>
另一个jobs.xml示例在Quartz发行版的examples / example10目录中。
检查XML Schema,了解可能的全部细节。
14、在Scheduler中列出所有Job作业
// enumerate each job group for(String group: sched.getJobGroupNames()) { // enumerate each job in group for(JobKey jobKey : sched.getJobKeys(groupEquals(group))) { System.out.println("Found job identified by: " + jobKey); } }
15、在Scheduler中列出所有Trigger触发器
// enumerate each trigger group for(String group: sched.getTriggerGroupNames()) { // enumerate each trigger in group for(TriggerKey triggerKey : sched.getTriggerKeys(groupEquals(group))) { System.out.println("Found trigger identified by: " + triggerKey); } }
16、查找一个Job关联的所有Trigger触发器
List<Trigger> jobTriggers = sched.getTriggersOfJob(jobKey("jobName", "jobGroup"));
17、使用JobListeners
创建JobListener,实现 JobListener 接口。
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobListener; public class MyJobListener implements JobListener { private String name; public MyJobListener(String name) { this.name = name; } public String getName() { return name; } public void jobToBeExecuted(JobExecutionContext context) { // do something with the event } public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { // do something with the event } public void jobExecutionVetoed(JobExecutionContext context) { // do something with the event } }
或者继承 JobListenerSupport。
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.listeners.JobListenerSupport; public class MyOtherJobListener extends JobListenerSupport { private String name; public MyOtherJobListener(String name) { this.name = name; } public String getName() { return name; } @Override public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { // do something with the event } }
Registering A JobListener With The Scheduler To Listen To All Jobs(所有Job)
scheduler.getListenerManager().addJobListener(myJobListener, allJobs());
Registering A JobListener With The Scheduler To Listen To A Specific Job(特定Job)
scheduler.getListenerManager().addJobListener(myJobListener, jobKeyEquals(jobKey("myJobName", "myJobGroup")));
Registering A JobListener With The Scheduler To Listen To All Jobs In a Group(特定组的所有Job)
scheduler.getListenerManager().addJobListener(myJobListener, jobGroupEquals("myJobGroup"));
参考阅读文章:Quartz 定时任务使用 —— JobListener、Triggerlistener、SchedulerListener(十三)
18、使用TriggerListeners
创建一个TriggerListener,实现 TriggerListener 接口。
import org.quartz.JobExecutionContext; import org.quartz.Trigger; import org.quartz.TriggerListener; import org.quartz.Trigger.CompletedExecutionInstruction; public class MyTriggerListener implements TriggerListener { private String name; public MyTriggerListener(String name) { this.name = name; } public String getName() { return name; } public void triggerComplete(Trigger trigger, JobExecutionContext context, CompletedExecutionInstruction triggerInstructionCode) { // do something with the event } public void triggerFired(Trigger trigger, JobExecutionContext context) { // do something with the event } public void triggerMisfired(Trigger trigger) { // do something with the event } public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) { // do something with the event return false; } }
或者继承 TriggerListenerSupport
import org.quartz.JobExecutionContext; import org.quartz.Trigger; import org.quartz.listeners.TriggerListenerSupport; public class MyOtherTriggerListener extends TriggerListenerSupport { private String name; public MyOtherTriggerListener(String name) { this.name = name; } public String getName() { return name; } @Override public void triggerFired(Trigger trigger, JobExecutionContext context) { // do something with the event } }
Registering A TriggerListener With The Scheduler To Listen To All Triggers(所有触发器)
scheduler.getListenerManager().addTriggerListener(myTriggerListener, allTriggers());
Registering A TriggerListener With The Scheduler To Listen To A Specific Trigger(特定触发器)
scheduler.getListenerManager() .addTriggerListener(myTriggerListener, triggerKeyEquals(triggerKey("myTriggerName", "myTriggerGroup")));
Registering A TriggerListener With The Scheduler To Listen To All Triggers In a Group(特定组的所有触发器)
scheduler.getListenerManager().addTriggerListener(myTriggerListener, triggerGroupEquals("myTriggerGroup"));
参考阅读文章:Quartz 定时任务使用 —— JobListener、Triggerlistener、SchedulerListener(十三)
19、使用SchedulerListeners
创建一个SchedulerListener,继承TriggerListenerSupport,重写您感兴趣的事件的方法。
import org.quartz.Trigger; import org.quartz.listeners.SchedulerListenerSupport; public class MyOtherSchedulerListener extends SchedulerListenerSupport { @Override public void schedulerStarted() { // do something with the event } @Override public void schedulerShutdown() { // do something with the event } @Override public void jobScheduled(Trigger trigger) { // do something with the event } }
注册SchedulerListener
scheduler.getListenerManager().addSchedulerListener(mySchedListener);
参考阅读文章:Quartz 定时任务使用 —— JobListener、Triggerlistener、SchedulerListener(十三)
20、触发器每10秒触发一次
使用 SimpleTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(simpleSchedule() .withIntervalInSeconds(10) .repeatForever()) .build();
21、触发器每90分钟触发一次
使用 SimpleTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(simpleSchedule() .withIntervalInMinutes(90) .repeatForever()) .build();
使用 CalendarIntervalTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(calendarIntervalSchedule() .withIntervalInMinutes(90)) .build();
22、每天触发的触发器
如果您希望在一天中的特定时间内始终触发触发器,请使用CronTrigger或CalendarIntervalTrigger,因为它们可以通过夏令时间来保留更改
使用 CronTrigger
创建一个CronTrigger。 每天下午3:00执行:
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(dailyAtHourAndMinute(15, 0)) // fire every day at 15:00 .build();
使用 SimpleTrigger
创建一个SimpleTrigger,执行明天3:00 PM,然后每24小时执行一次(可能并不总是在下午3:00),因为在夏令时可能导致下午2:00或下午4:00的24小时。 取决于3:00 PM时间是否在DST或标准时间内启动):
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();
使用 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();
23、触发器每2天触发一次
乍一看,您可能会试图使用CronTrigger。 但是,如果这是真正的每两天,CronTrigger将无法工作。 为了说明这一点,只要想一个典型的月份(28-31)几天。 像“0 0 5 2/2 *?”这样的cron表达式将给我们一个触发器,它将在每个月初重新开始计数。 这意味着我们将在7月30日和8月2日之间接下来的发射,这是三天的时间间隔,而不是两次。
同样,像“0 0 5 1/2 *?”一样的表达式将在7月31日和8月1日结束,只有一天的时间。
因此,对于这个时间表,使用SimpleTrigger或CalendarIntervalTrigger是有意义的:
使用 SimpleTrigger
创建一个SimpleTrigger,明天3:00 PM,然后每48小时执行一次(可能并不总是在3:00 PM),因为在夏令时可能导致2:00 PM或4:00 PM的24小时 取决于3:00 PM时间是否在DST或标准时间内启动):
trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(tomorrowAt(15, 0, 0) // first fire time 15:00:00 tomorrow .withSchedule(simpleSchedule() .withIntervalInHours(2 * 24) // interval is actually set at 48 hours' worth of milliseconds .repeatForever()) .build();
使用 CalendarIntervalTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(tomorrowAt(15, 0, 0) // 15:00:00 tomorrow .withSchedule(calendarIntervalSchedule() .withIntervalInDays(2)) // interval is set in calendar days .build();
24、每周触发的触发器
如果您想要在一天中的某个时间点始终触发的触发器,请使用CronTrigger或CalendarIntervalTrigger,因为它们可以通过夏令时来保留更改
使用 CronTrigger
创建一个CronTrigger。 每星期三下午3:00执行:
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(weeklyOnDayAndHourAndMinute(DateBuilder.WEDNESDAY, 15, 0)) // fire every wednesday at 15:00 .build();
或者
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(cronSchedule("0 0 15 ? * WED")) // fire every wednesday at 15:00 .build();
使用 SimpleTrigger
创建一个SimpleTrigger,执行明天3:00 PM,然后每7 * 24小时执行一次(可能不总是在3:00 PM),因为在夏令时可能导致2:00 PM或4: 00 PM取决于是否在DST或标准时间内启动3:00 PM时间):
trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(tomorrowAt(15, 0, 0) // first fire time 15:00:00 tomorrow .withSchedule(simpleSchedule() .withIntervalInHours(7 * 24) // interval is actually set at 7 * 24 hours' worth of milliseconds .repeatForever()) .build();
使用 CalendarIntervalTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(tomorrowAt(15, 0, 0) // 15:00:00 tomorrow .withSchedule(calendarIntervalSchedule() .withIntervalInWeeks(1)) // interval is set in calendar weeks .build();
25、触发器每2周触发一次
由于触发器意味着每两天触发一次,CronTrigger将不会为此计划工作。 有关详细信息,请参阅上面触发器每2天触发一次。 我们需要使用SimpleTrigger或CalendarIntervalTrigger:
使用 SimpleTrigger
创建一个SimpleTrigger,明天3:00 PM,然后每48小时执行一次(可能并不总是在3:00 PM),因为在夏令时可能导致2:00 PM或4:00 PM的24小时 取决于3:00 PM时间是否在DST或标准时间内启动):
trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(tomorrowAt(15, 0, 0) // first fire time 15:00:00 tomorrow .withSchedule(simpleSchedule() .withIntervalInHours(14 * 24) // interval is actually set at 14 * 24 hours' worth of milliseconds .repeatForever()) .build();
使用 CalendarIntervalTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(tomorrowAt(15, 0, 0) // 15:00:00 tomorrow .withSchedule(calendarIntervalSchedule() .withIntervalInWeeks(2)) // interval is set in calendar weeks .build();
26、触发器每月触发
使用 CronTrigger
创建一个CronTrigger。 每星期三下午3:00执行:
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(monthlyOnDayAndHourAndMinute(5, 15, 0)) // fire on the 5th day of every month at 15:00 .build();
或者
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(cronSchedule("0 0 15 5 * ?")) // fire on the 5th day of every month at 15:00 .build();
或者
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(cronSchedule("0 0 15 L * ?")) // fire on the last day of every month at 15:00 .build();
或者
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(cronSchedule("0 0 15 LW * ?")) // fire on the last weekday day of every month at 15:00 .build();
或者
trigger = newTrigger() .withIdentity("trigger3", "group1") .startNow() .withSchedule(cronSchedule("0 0 15 L-3 * ?")) // fire on the third to last day of every month at 15:00 .build();
还有其他可能的组合,这些组合在API文档中有更全面的介绍。 所有这些选项都是通过简单地更改月份字段来进行的。 想象一下,如果您利用其他领域,您可以做什么?
使用 CalendarIntervalTrigger
trigger = newTrigger() .withIdentity("trigger3", "group1") .startAt(tomorrowAt(15, 0, 0) // 15:00:00 tomorrow .withSchedule(calendarIntervalSchedule() .withIntervalInMonths(1)) // interval is set in calendar months .build();