1.觸發器(Triggers)
與Job相比,Trigger相對來說比較簡單容易,但是要能完全的掌握使用Quartz,使其包含各種自定義的時間表選項,我們必須先知道和理解Trigger。
1.1日歷(Calendars)
Quartz Calendar
對象(不是java.util.Calendar對象)能夠與被注冊進Scheduler的Trigger關聯。Calendar對排除Trigger的
時間段是很有用的,例如,我們可以創建一個在每個工作日上午9:30觸發Job的Trigger,就在其中增加一個排除所有工作假期的Calendar。
Calendar可以是任何實現Calendar接口的可序列化對象,如下所示:
package org.quartz;
public interface Calendar {
public boolean isTimeIncluded(long timeStamp);
public long getNextIncludedTime(long timeStamp);
}
該接口的參數都是long類型的,以毫秒為單位的timestamp;所以Calendar定義的時間可以準確到毫秒。很可能,我們需要排除一整天,為了方便,Quartz包含了實現該功能的類ori.quartz.impl.HolidayCalendar。
Calendar必須實例化并且通過addCalendar(…)方法注冊到Scheduler中,如果使用HolidayCalendar,在實例化之后,我們需要使用方法addExcludedDate(Date
date)排除我們計劃日程中不需要的日期,一個Calendar實例可以用到不同的Trigger中,比如:
HolidayCalendar cal = new HolidayCalendar();
cal.addExcludedDate( someDate );
sched.addCalendar("myHolidays", cal, false);
SimpleTrigger trigger = new SimpleTrigger("myTrigger",
sched.DEFAULT_GROUP,
new Date(),
null,
SimpleTrigger.REPEAT_INDEFINITELY,
60L * 1000L);
trigger.setCalendarName("myHolidays");
// .. schedule job with trigger
SimpleTrigger trigger2 = new SimpleTrigger("myTrigger",
sched.DEFAULT_GROUP,
new Date(),
null,
5,
5L * 24L * 60L * 60L * 1000L);
trigger2.setCalendarName("myHolidays");
// .. schedule job with trigger2
上面代碼,我們創建了兩個Trigger:一個是每1分鐘執行觸發一次,沒有次數限制;另一個是每5天執行觸發一次,共執行5次觸發;然而,任何在Calendar中被排除的時間段的觸發執行都將被取消。
1.2 過時觸發指令(Misfire
Instructions)
Trigger另一個重要的屬性是“Misfire
Instruction”。過時觸發發生在持久Trigger失去了觸發時間,由于對應的Scheduler被關閉的原因;不同的Trigger類型有不
同的過時觸發指令,默認情況下是使用“smart
policy”指令,該指令根據Trigger類型和配置具有動態的行為。當scheduler啟動時,它將搜索所有過時觸發的持久Trigger,并同
時根據它們各自所配置的過時觸發指令進行更新;當我們在項目中要使用Quartz時,我們必須熟悉所要使用的Trigger類型的過時觸發指示,在對應的
JavaDOC中有對其進行說明。可以通過方法setMisfireInstruction(…)來設置Trigger的過時觸發指示。
1.3 觸發器的輔助類(TriggerUtils)
TriggerUtils類(在org.quartz.helpers包中)為我們創建Trigger和觸發時間提供了方便,可以使我們不用
java.util.Calendar對象。使用輔助類能夠很容易地創建基于每分鐘、小時、天、周和月等觸發的觸發器,也可以創建各種各樣的日期――對設
置觸發器的啟動時間很有用。
1.4觸發器的監聽器(TriggerListeners)
Trigger能夠像Job一樣,可以把監聽器注冊到Trigger中,實現了接口TriggerListener的對象就可以接收到Trigger觸發時的通知。
2.Simple觸發器(SimpleTrigger)
當我們需要在規定的時間執行一次或在規定的時間段以一定的時間間隔重復觸發執行Job時,SimpleTrigger就可以滿足上述要求。
SimpleTrigger的屬性有:開始時間、結束時間、重復次數和重復的時間間隔,重復次數屬性的值可以為0、正整數、或常量
SimpleTrigger.REPEAT_INDEFINITELY,重復的時間間隔屬性值必須為0或長整型的正整數,以毫秒作為時間單位,當重復的時
間間隔為0時,意味著與Trigger同時觸發執行(或幾乎與Scheduler開始時同時觸發執行)。
如果有指定結束時間屬性值,則結束時間屬性優先于重復次數屬性,這樣的好處在于:當我們需要創建一個每間隔10秒鐘觸發一次直到指定的結束時間的
Trigger,而無需去計算從開始到結束的所重復的次數,我們只需簡單的指定結束時間和使用REPEAT_INDEFINITELY作為重復次數的屬性
值即可(我們也可以指定一個比在指定結束時間到達時實際執行次數大的重復次數)。
SimpleTrigger有幾個不同的構造方法,我們只對下面這個進行分析:
public SimpleTrigger(String name, String group, Date startTime, Date endTime, int repeatCount, long repeatInterval)
SimpleTrigger例1――創建一個在當前之后10秒鐘觸發的,執行一次的Trigger
long startTime = System.currentTimeMillis() + 10000L;
SimpleTrigger trigger = new SimpleTrigger("myTrigger",
sched.DEFAULT_GROUP,
new Date(startTime),
null,
0,
0L);
SimpleTrigger例2――創建一個立即觸發的,并每間隔60秒鐘重復觸發執行一次的Trigger
SimpleTrigger trigger = new
SimpleTrigger(”myTrigger”,
sched.DEFAULT_GROUP,
new Date(),
null,
SimpleTrigger.REPEAT_INDEFINITELY,
60L * 1000L);
SimpleTrigger例3――創建一個立即觸發,每間隔10秒鐘重復觸發執行一次,開始時間為當前,結束時間為40秒鐘后的Trigger
long endTime = System.currentTimeMillis() + 40000L;
SimpleTrigger trigger = new SimpleTrigger("myTrigger",
sched.DEFAULT_GROUP,
new Date(),
new Date(endTime),
SimpleTrigger.REPEAT_INDEFINITELY,
10L * 1000L);
SimpleTrigger例4――創建一個在2005年5月8日早上10:30觸發的,每間隔30秒鐘重復觸發執行一次,并且重復執行5次(總共觸發執行6次)的Trigger
java.util.Calendar cal = new java.util.GregorianCalendar(2005, cal.MAY, 8);
cal.set(cal.HOUR, 10);
cal.set(cal.MINUTE, 30);
cal.set(cal.SECOND, 0);
cal.set(cal.MILLISECOND, 0);
Data startTime = cal.getTime()
SimpleTrigger trigger = new SimpleTrigger("myTrigger",
sched.DEFAULT_GROUP,
startTime,
null,
5,
30L * 1000L);
2.1 Simple觸發器的過時觸發指令(SimpleTrigger
Misfire Instructions)
SimpleTrigger有幾個用于當過時觸發發生時向Quartz通知如何執行的指令,這些指令作為常量定義在SimpleTrigger類中,分別如下:
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的默認值。
如果使用“smart policy”,SimpleTrigger將會根據實例中的配置進行動態的選擇過時觸發指令,JavaDOC中的SimpleTrigger.updateAfterMisfire()方法詳細解析了動態選擇的內容。
3.Cron觸發器(CronTrigger)
CronTrigger的功能比SimpleTrigger強大,它可以實現基于類似于日歷概念的作業調度,而不是單單基于一定的時間間隔的。
使用CronTrigger,我們能夠定義如下類型的日歷型的Schedule:每個星期五的中午,每個周末的早上9:30,或者每周一、周三和周五的早上9:00到10:00每隔5分鐘。
3.1 Cron表達式(Cron Expressions)
Cron-Expressions用于配置CronTrigger實例,Cron-Expressions是一串字符串,實際上它由六個子字符串組成,子字符串間采用空格分離,從左到右分別代表:Seconds Minutes Hours Day-of-Month Month Day-of-Week。
字符串“0 0 12 ? * WED”是一個完整的Cron-Expressions例子,它所表達的意思是:每周三早上12:00。
各個子表達式的值可以是一個范圍或者列表,比如,上個例子中的Day-of-Week域的值“WED”可以用“MON-FRI”、“MON,WED,FRI”或者“MON-WED,SAT”來替代。
所有子表達式都有指定各自的取值范圍,下面對Cron-Expressions的各個子表達式和取值范圍進行說明:
子表達式
|
允許的值
|
允許的特殊字符
|
Seconds
|
0-59
|
- * /
|
Minutes
|
0-59
|
- * /
|
Hours
|
0-23
|
- * /
|
Day-of-Month
|
1-31
|
- * ? / L W
|
Month
|
1-12或JAN-DEC
|
- * /
|
Day-of-Week
|
1-7或SUN-SAT
|
- * ? / L #
|
Years(Optional)
|
為空或1970-2099
|
- * /
|
‘-’字符表示:值的范圍,10-12在Hours域中表示為:10、11和12;
‘*’字符表示:可以為任意值,‘*’在Minutes域中表示為:每分鐘;
‘/’字符表示:一個左邊的數值是右邊基數的遞增值,‘0/15’在Seconds域中表示為:第0、15、30和45秒,‘5/15’
在Seconds域中表示為:第5、20、35和50;
‘?’字符表示:沒有對該域指定值,可以為任意值,不對該域進行限制,‘?’只能用在Day-of-Month和Day-of-Week域中;
‘L’字符表示:‘L’是取‘Last’的第一個字母,也只能用在Day-of-Month和Day-of-Week域中,在Day-of-Month域
中的意思是:月份的最后一天,在Day-of-Week域中的意思是:‘7’或‘SAT’,但是在Day-of-Week域中用在另一個值后的意思是:該
月的最后一個星期幾,如:‘6L’為:該月的最后一個星期五;
‘W’字符表示:‘W’是取‘Weekday’的第一個字母,只能用在Day-of-Month域中,‘W’代表了最接近給定那一天的工作日,如:在
Day-of-Month域中把值設為:15W,表示的意思是:該月的第15日最接近的工作日,所以當第15日是周六時,Trigger將在第14日的周
五執行觸發,當第15日是周天時,Trigger將在第16日的周一執行觸發,當第15日是工作日時,Trigger將在第15日的當天執行觸發;然而在
Day-of-Month域中把值設為:1W,當第1日是周六時,Trigger將在第3日的周一執行觸發,因為它不會跨越月份的范圍,‘W’字符只能是
該月中的一天,而不是一個范圍或天數的列表;在Day-of-Month
域中可以結合使用‘L’和‘W’字符‘LW’,‘LW’表示:月份的最后一個工作日;
‘#’字符表示:月份的第幾個星期幾,只能用在Day-of-Week域中,如:在Day-of-Week域中把值設為:6#3,表示的意思是:該月的第3個星期5(day
6=Friday and “#3”=the 3rd one in the
month);2#1表示的意思是:該月的第1個星期1;4#5表示的意思是:該月的第5個星期3;需要注意:不能把值設為“#5”,因為一個月中不可能有第5個星期3,如果這樣設置,將導致該月無法執行觸發;
下面舉一些完整的Cron- Expressions例子:
表達式
|
意思
|
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每隔1分鐘執行一次觸發 |
0 0/5 14 * * ? |
每天從14:00到14:59每個5分鐘執行一次觸發 |
0 0/5 14,18 * * ? |
每天從14:00到14:59和18:00到18:59每隔5分鐘執行一次觸發 |
0 0-5 14 * * ? |
每天從14:00到14:05每隔1分鐘執行一次觸發 |
0 10,44 14 ? 3 WED |
3月的每個星期3的14:10和14:44分別執行一次觸發 |
0 15 10 15 * ? |
每月的第15日10:15執行一次觸發 |
0 15 10 L * ? |
每月最后一天的10:15執行一次觸發 |
0 15 10 ? * 6L |
每月的最后一個星期5的10:15執行一次觸發 |
0 15 10 ? * 2002-2005 |
2002、2003、2004、2005年的每個月的最后一個星期5的10:15執行一次觸發 |
0 15 10 ? * 6#3 |
每月的第3個星期5的10:15執行一次觸發 |
當Schedule中要求比較復雜,采用單個的Trigger無法實現時,可以配置多個的Trigger來實現,比如:每天的9:00到10:00之間每
隔5分鐘執行一次觸發,并且在每天的13:00到22:00之間每隔20分鐘執行一次觸發,配置2個Trigger并把2配置好的2個Trigger注冊
到相同的Job中就可以很簡單的實現上述情況。
讓我們繼續用第一個例子中StringTest.
1.來寫一個每隔10秒啟動一次任務的例子.
import java.util.Date;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;

public class SimpleTriggerTest


{

public static void main(String[] args) throws Exception

{
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 系統當前時間10秒后
long startTime = System.currentTimeMillis() + 10000L;
SimpleTrigger trigger = new SimpleTrigger("myTrigger", null, new Date(
startTime), null, 0, 0L);

JobDetail jobDetail = new JobDetail();
jobDetail.setJobClass(StringTest.class);
jobDetail.setName("test");
jobDetail.setGroup("A");

scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}
}

2.創建一個觸發器,立即啟動,每隔60秒,啟動一次.
SimpleTrigger trigger = new SimpleTrigger("myTrigger",
null,
new Date(),
null,
SimpleTrigger.REPEAT_INDEFINITELY,
60L * 1000L);

3.創建一個觸發器,立即啟動.從現在開始的第10秒到第40秒重復運行.
long endTime = System.currentTimeMillis() + 40000L;

SimpleTrigger trigger = new SimpleTrigger("myTrigger",
"myGroup",
new Date(),
new Date(endTime),
SimpleTrigger.REPEAT_INDEFINITELY,
10L * 1000L);
4.創建一個觸發器,在2008年5月9日,上午10點半執行,重復5次,每隔30秒一次.
java.util.Calendar cal = new java.util.GregorianCalendar(2008, cal.MARCH, 9);
cal.set(cal.HOUR, 10);
cal.set(cal.MINUTE, 30);
cal.set(cal.SECOND, 0);
cal.set(cal.MILLISECOND, 0);

Data startTime = cal.getTime()

SimpleTrigger trigger = new SimpleTrigger("myTrigger",
null,
startTime,
null,
5,
30L * 1000L);
仔細體會SimpleTrigger的例子,你會發現用這個制作執行計劃會更簡單方便.
一個小例子,
DelayTest class
---------------
package test.com.bsmart.bmc.operator.taxi;
import java.util.Date;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;
public class DelayTest {
public void addDelayJob(){
SchedulerFactory scheFact = new StdSchedulerFactory();
Scheduler sche = null;
try {
sche = scheFact.getScheduler();
sche.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
JobDetail jobDetail = new JobDetail("myJob","job1",JobTest.class);
// JobTest jobTest = new JobTest();
SimpleTrigger trigger = new SimpleTrigger("test","testGroup",new Date(new Date().getTime()+5*1000),null,5,10*1000);
try {
sche.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
public static void main(String [] args){
DelayTest test = new DelayTest();
test.addDelayJob();
}
}
job class
-------------------------------------------------
package test.com.bsmart.bmc.operator.taxi;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;
public class JobTest implements Job{
// private SimpleTrigger trigger;
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("********************************8");
System.out.println("********************************8");
System.out.println("********** job test *******8");
System.out.println("********************************8");
System.out.println("********************************8");
System.out.println("name="+arg0.getJobDetail().getName());
System.out.println("fullname="+arg0.getJobDetail().getFullName());
System.out.println("description="+arg0.getJobDetail().getDescription());
System.out.println();
System.out.println("********************************8");
System.out.println("*********** delete the job *********8");
SchedulerFactory scheFact = new StdSchedulerFactory();
Scheduler sche = null;
boolean tag = false;
try {
sche = scheFact.getScheduler();
// sche.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
// try {
// tag = sche.deleteJob("myJob","job1");
// } catch (SchedulerException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
if(tag){
System.out.println("delete job sucess");
}else{
System.out.println("delete job failed");
}
}
}