More About Triggers
refer to: http://www.quartz-scheduler.org/documentation/2.3.1-SNAPSHOT/tutorials/tutorial-lesson-04.html
Like jobs, triggers are quite easy to work with, but do contain a variety of customizable options that you need to be aware of and understand before you can make full use of Quartz. Also, as noted earlier, there are different types of triggers that you can select from to meet different scheduling needs.
You will learn about the two most common types of triggers in Lesson 5: Simple Triggers and Lesson 6: Cron Triggers.
Common Trigger Attributes
Aside from the fact that all trigger types have TriggerKey properties for tracking their identities, there are a number of other properties that are common to all trigger types. These common properties are set using the TriggerBuilder when you are building the trigger definition (examples of that will follow).
Here is a listing of properties common to all trigger types:
-
The “jobKey” property indicates the identity of the job that should be executed when the trigger fires.
-
The “startTime” property indicates when the trigger’s schedule first comes into affect. The value is a java.util.Date object that defines a moment in time on a given calendar date. For some trigger types, the trigger will actually fire at the start time, for others it simply marks the time that the schedule should start being followed. This means you can store a trigger with a schedule such as “every 5th day of the month” during January, and if the startTime property is set to April 1st, it will be a few months before the first firing.
-
The “endTime” property indicates when the trigger’s schedule should no longer be in effect. In other words, a trigger with a schedule of “every 5th day of the month” and with an end time of July 1st will fire for it’s last time on June 5th.
Other properties, which take a bit more explanation are discussed in the following sub-sections.
Priority
Sometimes, when you have many Triggers (or few worker threads in your Quartz thread pool), Quartz may not have enough resources to immediately fire all of the Triggers that are scheduled to fire at the same time. In this case, you may want to control which of your Triggers get first crack at the available Quartz worker threads. For this purpose, you can set the priority property on a Trigger. If N Triggers are to fire at the same time, but there are only Z worker threads currently available, then the first Z Triggers with the highest priority will be executed first. If you do not set a priority on a Trigger, then it will use the default priority of 5. Any integer value is allowed for priority, positive or negative.
Note: Priorities are only compared when triggers have the same fire time. A trigger scheduled to fire at 10:59 will always fire before one scheduled to fire at 11:00.
Note: When a trigger’s job is detected to require recovery, its recovery is scheduled with the same priority as the original trigger.
Calendars
Quartz Calendar objects (not java.util.Calendar objects) can be associated with triggers at the time the trigger is defined and stored in the scheduler. Calendars are useful for excluding blocks of time from the the trigger’s firing schedule. For instance, you could create a trigger that fires a job every weekday at 9:30 am, but then add a Calendar that excludes all of the business’s holidays.
Calendar’s can be any serializable objects that implement the Calendar interface, which looks like this:
The Calendar Interface
package org.quartz;
public interface Calendar {
public boolean isTimeIncluded(long timeStamp);
public long getNextIncludedTime(long timeStamp);
}
Notice that the parameters to these methods are of the long type. As you may guess, they are timestamps in millisecond format. This means that calendars can ‘block out’ sections of time as narrow as a millisecond. Most likely, you’ll be interested in ‘blocking-out’ entire days. As a convenience, Quartz includes the class org.quartz.impl.HolidayCalendar, which does just that.
Calendars must be instantiated and registered with the scheduler via the addCalendar(…) method. If you use HolidayCalendar, after instantiating it, you should use its addExcludedDate(Date date) method in order to populate it with the days you wish to have excluded from scheduling. The same calendar instance can be used with multiple triggers such as this:
Calendar Example
HolidayCalendar cal = new HolidayCalendar();
cal.addExcludedDate( someDate );
cal.addExcludedDate( someOtherDate );
sched.addCalendar("myHolidays", cal, 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
The details of the construction/building of triggers will be given in the next couple lessons. For now, just believe that the code above creates two triggers, each scheduled to fire daily. However, any of the firings that would have occurred during the period excluded by the calendar will be skipped.
See the org.quartz.impl.calendar package for a number of Calendar implementations that may suit your needs.
SimpleTrigger
refer to : http://www.quartz-scheduler.org/documentation/2.3.1-SNAPSHOT/tutorials/tutorial-lesson-05.html
SimpleTrigger should meet your scheduling needs if you need to have a job execute exactly once at a specific moment in time, or at a specific moment in time followed by repeats at a specific interval. For example, if you want the trigger to fire at exactly 11:23:54 AM on January 13, 2015, or if you want it to fire at that time, and then fire five more times, every ten seconds.
With this description, you may not find it surprising to find that the properties of a SimpleTrigger include: a start-time, and end-time, a repeat count, and a repeat interval. All of these properties are exactly what you’d expect them to be, with only a couple special notes related to the end-time property.
The repeat count can be zero, a positive integer, or the constant value SimpleTrigger.REPEAT_INDEFINITELY. The repeat interval property must be zero, or a positive long value, and represents a number of milliseconds. Note that a repeat interval of zero will cause ‘repeat count’ firings of the trigger to happen concurrently (or as close to concurrently as the scheduler can manage).
If you’re not already familiar with Quartz’s DateBuilder class, you may find it helpful for computing your trigger fire-times, depending on the startTime (or endTime) that you’re trying to create.
The endTime property (if it is specified) overrides the repeat count property. This can be useful if you wish to create a trigger such as one that fires every 10 seconds until a given moment in time - rather than having to compute the number of times it would repeat between the start-time and the end-time, you can simply specify the end-time and then use a repeat count of REPEAT_INDEFINITELY (you could even specify a repeat count of some huge number that is sure to be more than the number of times the trigger will actually fire before the end-time arrives).
SimpleTrigger instances are built using TriggerBuilder (for the trigger’s main properties) and SimpleScheduleBuilder (for the SimpleTrigger-specific properties). To use these builders in a DSL-style, use static imports:
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.DateBuilder.*:
注意下:
SimpleScheduleBuilder、 TriggerBuilder、SchedulerFactory 这3者是什么关系呢?
SimpleScheduleBuilder 和 TriggerBuilder 都是用于创建和配置Trigger的
而SchedulerFactory 是用于创建Scheduler的
SimpleScheduleBuilder 是辅助 TriggerBuilder的,SimpleScheduleBuilder是用于指定RepeatInterval、RepeatCount等参数的,然后会在创建Trigger的时候,提供这些参数,方便创建Trigger。
代码如下:
// org.quartz.SimpleScheduleBuilder#build
@Override
public MutableTrigger build() {
SimpleTriggerImpl st = new SimpleTriggerImpl();
st.setRepeatInterval(interval);
st.setRepeatCount(repeatCount);
st.setMisfireInstruction(misfireInstruction);
return st;
}
Here are various examples of defining triggers with simple schedules, read through them all, as they each show at least one new/different point:
Build a trigger for a specific moment in time, with no repeats:
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger1", "group1")
.startAt(myStartTime) // some Date
.forJob("job1", "group1") // identify job with name, group strings
.build();
Build a trigger for a specific moment in time, then repeating every ten seconds ten times:
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();
Build a trigger that will fire once, five minutes in the future:
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();
Build a trigger that will fire now, then repeat every five minutes, until the hour 22:00:
trigger = newTrigger()
.withIdentity("trigger7", "group1")
.withSchedule(simpleSchedule()
.withIntervalInMinutes(5)
.repeatForever())
.endAt(dateOf(22, 0, 0))
.build();
Build a trigger that will fire at the top of the next hour, then repeat every 2 hours, forever:
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);
Spend some time looking at all of the available methods in the language defined by TriggerBuilder and SimpleScheduleBuilder so that you can be familiar with options available to you that may not have been demonstrated in the examples above.
Note that TriggerBuilder (and Quartz’s other builders) will generally choose a reasonable value for properties that you do not explicitly set. For examples: if you don’t call one of the withIdentity(…) methods, then TriggerBuilder will generate a random name for your trigger; if you don’t call startAt(…) then the current time (immediately) is assumed.
CronTrigger
refer to: http://www.quartz-scheduler.org/documentation/2.3.1-SNAPSHOT/tutorials/tutorial-lesson-06.html
CronTrigger is often more useful than SimpleTrigger, if you need a job-firing schedule that recurs based on calendar-like notions, rather than on the exactly specified intervals of SimpleTrigger.
With CronTrigger, you can specify firing-schedules such as “every Friday at noon”, or “every weekday and 9:30 am”, or even “every 5 minutes between 9:00 am and 10:00 am on every Monday, Wednesday and Friday during January”.
Even so, like SimpleTrigger, CronTrigger has a startTime which specifies when the schedule is in force, and an (optional) endTime that specifies when the schedule should be discontinued.
Cron Expressions
Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up of seven sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent:
- Seconds
- Minutes
- Hours
- Day-of-Month
- Month
- Day-of-Week
- Year (optional field)
An example of a complete cron-expression is the string “0 0 12 ? * WED” - which means “every Wednesday at 12:00:00 pm”.
Individual sub-expressions can contain ranges and/or lists. For example, the day of week field in the previous (which reads “WED”) example could be replaced with “MON-FRI”, “MON,WED,FRI”, or even “MON-WED,SAT”.
Wild-cards (the *
character) can be used to say “every” possible value of this field.
Therefore the *
character in the “Month” field of the previous example simply means “every month”.
A ‘*’ in the Day-Of-Week field would therefore obviously mean “every day of the week”.
All of the fields have a set of valid values that can be specified. These values should be fairly obvious - such as the numbers 0 to 59 for seconds and minutes, and the values 0 to 23 for hours. Day-of-Month can be any value 1-31, but you need to be careful about how many days are in a given month! Months can be specified as values between 0 and 11, or by using the strings JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Days-of-Week can be specified as values between 1 and 7 (1 = Sunday) or by using the strings SUN, MON, TUE, WED, THU, FRI and SAT.
The ‘/’ character can be used to specify increments to values. For example, if you put ‘0/15’ in the Minutes field, it means ‘every 15th minute of the hour, starting at minute zero’. If you used ‘3/20’ in the Minutes field, it would mean ‘every 20th minute of the hour, starting at minute three’ - or in other words it is the same as specifying ‘3,23,43’ in the Minutes field. Note the subtlety that “/35” does *not mean “every 35 minutes” - it mean “every 35th minute of the hour, starting at minute zero” - or in other words the same as specifying ‘0,35’.
The ‘?’ character is allowed for the day-of-month and day-of-week fields. It is used to specify “no specific value”. This is useful when you need to specify something in one of the two fields, but not the other. See the examples below (and CronTrigger JavaDoc) for clarification.
The ‘L’ character is allowed for the day-of-month and day-of-week fields. This character is short-hand for “last”, but it has different meaning in each of the two fields. For example, the value “L” in the day-of-month field means “the last day of the month” - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means “7” or “SAT”. But if used in the day-of-week field after another value, it means “the last xxx day of the month” - for example “6L” or “FRIL” both mean “the last friday of the month”. You can also specify an offset from the last day of the month, such as “L-3” which would mean the third-to-last day of the calendar month. When using the ‘L’ option, it is important not to specify lists, or ranges of values, as you’ll get confusing/unexpected results.
The ‘W’ is used to specify the weekday (Monday-Friday) nearest the given day. As an example, if you were to specify “15W” as the value for the day-of-month field, the meaning is: “the nearest weekday to the 15th of the month”.
The ‘#’ is used to specify “the nth” XXX weekday of the month. For example, the value of “6#3” or “FRI#3” in the day-of-week field means “the third Friday of the month”.
Here are a few more examples of expressions and their meanings - you can find even more in the JavaDoc for org.quartz.CronExpression
Example Cron Expressions
CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes
“0 0/5 * * * ?”
CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.).
“10 0/5 * * * ?”
CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday.
“0 30 10-13 ? * WED,FRI”
CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month. Note that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30
“0 0/30 8-9 5,20 * ?”
Note that some scheduling requirements are too complicated to express with a single trigger - such as “every 5 minutes between 9:00 am and 10:00 am, and every 20 minutes between 1:00 pm and 10:00 pm”. The solution in this scenario is to simply create two triggers, and register both of them to run the same job.
Building CronTriggers
CronTrigger instances are built using TriggerBuilder (for the trigger’s main properties) and CronScheduleBuilder (for the CronTrigger-specific properties). To use these builders in a DSL-style, use static imports:
import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*;
Build a trigger that will fire every other minute, between 8am and 5pm, every day:
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 0/2 8-17 * * ?"))
.forJob("myJob", "group1")
.build();
Build a trigger that will fire daily at 10:42 am:
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(dailyAtHourAndMinute(10, 42))
.forJob(myJobKey)
.build();
or
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 42 10 * * ?"))
.forJob(myJobKey)
.build();
Build a trigger that will fire on Wednesdays at 10:42 am, in a TimeZone other than the system’s default:
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(weeklyOnDayAndHourAndMinute(DateBuilder.WEDNESDAY, 10, 42))
.forJob(myJobKey)
.inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
.build();
or
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 42 10 ? * WED"))
.inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
.forJob(myJobKey)
.build();