国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Quartz學(xué)習(xí)
  Quartz學(xué)習(xí)收藏
Quartz學(xué)習(xí)
介紹Quartz
Quartz是一個(gè)開源的任務(wù)調(diào)度系統(tǒng),它能用來調(diào)度很多任務(wù)的執(zhí)行。
運(yùn)行環(huán)境
Quartz 能嵌入在其他應(yīng)用程序里運(yùn)行。
Quartz 能在一個(gè)應(yīng)用服務(wù)器里被實(shí)例化(或servlet容器), 并且參與XA事務(wù)
Quartz能獨(dú)立運(yùn)行(通過JVM),或者通過RMI
Quartz能被集群實(shí)例化
任務(wù)調(diào)度
當(dāng)一個(gè)指定給任務(wù)的觸發(fā)器發(fā)生時(shí),任務(wù)就被調(diào)度執(zhí)行. 觸發(fā)器能被創(chuàng)建為:
一天的某個(gè)時(shí)間(精確到毫秒級(jí))
一周的某些天
一個(gè)月的某些天
一年的某些天
不在一個(gè)Calendar列出的某些天 (例如工作節(jié)假日)
在一個(gè)指定的次數(shù)重復(fù)
重復(fù)到一個(gè)指定的時(shí)間/日期
無限重復(fù)
在一個(gè)間隔內(nèi)重復(fù)
能夠給任務(wù)指定名稱和組名.觸發(fā)器也能夠指定名稱和組名,這樣可以很好的在調(diào)度器里組織起來.一個(gè)加入到調(diào)度器里的任務(wù)可以被多個(gè)觸發(fā)器注冊(cè)。在J2EE環(huán)境里,任務(wù)能作為一個(gè)分布式(XA)事務(wù)的一部分來執(zhí)行。
任務(wù)執(zhí)行
任務(wù)能夠是任何實(shí)現(xiàn)Job接口的Java類。
任務(wù)類能夠被Quartz實(shí)例化,或者被你的應(yīng)用框架。
當(dāng)一個(gè)觸發(fā)器觸發(fā)時(shí),調(diào)度器會(huì)通知實(shí)例化了JobListener 和TriggerListener 接口的0個(gè)或者多個(gè)Java對(duì)象(監(jiān)聽器可以是簡單的Java對(duì)象, EJBs, 或JMS發(fā)布者等). 在任務(wù)執(zhí)行后,這些監(jiān)聽器也會(huì)被通知。
當(dāng)任務(wù)完成時(shí),他們會(huì)返回一個(gè)JobCompletionCode ,這個(gè)代碼告訴調(diào)度器任務(wù)執(zhí)行成功或者失敗.這個(gè)代碼 也會(huì)指示調(diào)度器做一些動(dòng)作-例如立即再次執(zhí)行任務(wù)。
任務(wù)持久化
Quartz的設(shè)計(jì)包含JobStore接口,這個(gè)接口能被實(shí)現(xiàn)來為任務(wù)的存儲(chǔ)提供不同的機(jī)制。
應(yīng)用JDBCJobStore, 所有被配置成“穩(wěn)定”的任務(wù)和觸發(fā)器能通過JDBC存儲(chǔ)在關(guān)系數(shù)據(jù)庫里。
應(yīng)用RAMJobStore, 所有任務(wù)和觸發(fā)器能被存儲(chǔ)在RAM里因此不必在程序重起之間保存-一個(gè)好處就是不必使用數(shù)據(jù)庫。
事務(wù)
使用JobStoreCMT(JDBCJobStore的子類),Quartz 能參與JTA事務(wù)。
Quartz 能管理JTA事務(wù)(開始和提交)在執(zhí)行任務(wù)之間,這樣,任務(wù)做的事就可以發(fā)生在JTA事務(wù)里。
集群
Fail-over.
Load balancing.
監(jiān)聽器和插件
通過實(shí)現(xiàn)一個(gè)或多個(gè)監(jiān)聽接口,應(yīng)用程序能捕捉調(diào)度事件來監(jiān)控或控制任務(wù)/觸發(fā)器的行為。
插件機(jī)制可以給Quartz增加功能,例如保持任務(wù)執(zhí)行的歷史記錄,或從一個(gè)定義好的文件里加載任務(wù)和觸發(fā)器。
Quartz 裝配了很多插件和監(jiān)聽器。
1.使用Quartz
在我們用調(diào)度器之前,調(diào)度器需要實(shí)例化。我們用SchedulerFactory 來實(shí)例它。一旦調(diào)度器被實(shí)例,我們就可以啟動(dòng)它,置它為stand-by模式,最后關(guān)閉它。注意:一旦一個(gè)調(diào)度器被關(guān)閉了,如果我們不重新實(shí)例化它,它就不可能被再次啟動(dòng)。直到調(diào)度器啟動(dòng)了或者當(dāng)調(diào)度器處于暫停狀態(tài),觸發(fā)器才能夠觸發(fā)。下面有個(gè)簡單的例子:
SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
Scheduler sched = schedFact.getScheduler();
sched.start();
JobDetail jobDetail = new JobDetail("myJob",
null,
DumbJob.class);
Trigger trigger = TriggerUtils.makeHourlyTrigger(); // 每個(gè)小時(shí)觸發(fā)
trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date())); // 在下個(gè)小時(shí)開始
trigger.setName("myTrigger");
sched.scheduleJob(jobDetail, trigger);
就象你看到的,使用Quartz是很簡單的。在下一節(jié)我們介紹Jobs和Triggers。
2.Jobs 和 Triggers
就象以前提到的,一個(gè)實(shí)現(xiàn)了Job接口的Java類就能夠被調(diào)度器執(zhí)行。接口如下:
package org.quartz;
public interface Job {
public void execute(JobExecutionContext context) throws JobExecutionException;
}
很簡的,當(dāng)Job的trigger觸發(fā)時(shí),Job的execute(..)方法就會(huì)被調(diào)度器調(diào)用。被傳遞到這個(gè)方法里來的JobExecutionContext對(duì)象提供了帶有job運(yùn)行時(shí)的信息:執(zhí)行它的調(diào)度器句柄、觸發(fā)它的觸發(fā)器句柄、job的JobDetail對(duì)象和一些其他的項(xiàng)。
JobDetail對(duì)象是Job在被加到調(diào)度器里時(shí)所創(chuàng)建的,它包含有很多的Job屬性設(shè)置,和JobDataMap一樣,可以用來存儲(chǔ)job實(shí)例時(shí)的一些狀態(tài)信息。
Trigger對(duì)象是用來觸發(fā)執(zhí)行Job的。當(dāng)調(diào)度一個(gè)job時(shí),我們實(shí)例一個(gè)觸發(fā)器然后調(diào)整它的屬性來滿足job執(zhí)行的條件。觸發(fā)器也有一個(gè)和它相關(guān)的JobDataMap,它是用來給被觸發(fā)器觸發(fā)的job傳參數(shù)的。Quartz有一些不同的觸發(fā)器類型,不過,用得最多的是SimpleTrigger和CronTrigger。
如果我們需要在給定時(shí)刻執(zhí)行一次job或者在給定時(shí)刻觸發(fā)job隨后間斷一定時(shí)間不停的執(zhí)行的話,SimpleTrigger是個(gè)簡單的解決辦法;如果我們想基于類似日歷調(diào)度的觸發(fā)job的話,比如說,在每個(gè)星期五的中午或者在每個(gè)月第10天的10:15觸發(fā)job時(shí),CronTrigger是很有用的。
為什么用jobs和triggers呢?很多任務(wù)調(diào)度器并沒有任務(wù)和觸發(fā)器的概念,一些任務(wù)調(diào)度器簡單定義一個(gè)“job”為在一個(gè)執(zhí)行時(shí)間伴隨一些小任務(wù)標(biāo)示,其他的更像Quartz里job和trigger對(duì)象的聯(lián)合體。在開發(fā)Quartz時(shí),開發(fā)者們決定,在調(diào)度時(shí)間表和在這上面運(yùn)行的工作應(yīng)該分開。這是很有用的。
例如,job能夠獨(dú)立于觸發(fā)器被創(chuàng)建和儲(chǔ)存在任務(wù)調(diào)度器里,并且,很多的觸發(fā)器能夠與同一個(gè)job關(guān)聯(lián)起來。這個(gè)松耦合的另一個(gè)好處就是在與jobs關(guān)聯(lián)的觸發(fā)器終止后,我們能夠再次配置保留在調(diào)度器里的jobs,這樣的話,我們能夠再次調(diào)度這些jobs而不需要重新定義他們。我們也可以在不重新定義一個(gè)關(guān)聯(lián)到j(luò)ob的觸發(fā)器的情況下,修改或替代它。
當(dāng)Jobs和triggers被注冊(cè)到Quartz的調(diào)度器里時(shí),他們就有了唯一標(biāo)示符。他們也可以被放到“groups”里,Groups是用來組織分類jobs和triggers的,以便今后的維護(hù)。在一個(gè)組里的job和trigger的名字必須是唯一的,換句話說,一個(gè)job和trigger的全名為他們的名字加上組名。如果把組名置為”null”,系統(tǒng)會(huì)自動(dòng)給它置為Scheduler.DEFAULT_GROUP
現(xiàn)在,我們大概有了一些jobs和triggers的理解,隨后2節(jié)我們將根多的了解它們。
3.更多關(guān)于Jobs & JobDetails
Jobs很容易實(shí)現(xiàn),這兒有更多我們需要理解的東西:jobs的本質(zhì),job接口的execute(..)方法,關(guān)于JobDetails。
當(dāng)我們實(shí)現(xiàn)的一個(gè)class是真正的”job”時(shí),Quartz需要知道各種job有的屬性,這是通過JobDetail類做到的。在沒用JobDetail之前,JobDetail的功能的實(shí)現(xiàn)是通過在每個(gè)job的實(shí)現(xiàn)類上加上所有的現(xiàn)在JobDetail的get方法來實(shí)現(xiàn)的。這就在每個(gè)job類上強(qiáng)加了一些實(shí)現(xiàn)一樣功能的代碼,就顯得每個(gè)job類很笨重,于是,Quartz開發(fā)者們就創(chuàng)造了JobDetail類。
現(xiàn)在,我們來討論一下在Quartz里job的本質(zhì)和job實(shí)例的生命周期。首先我們來看看第一節(jié)的代碼片段:
JobDetail jobDetail = new JobDetail("myJob",      // job 名稱
sched.DEFAULT_GROUP, // job組名(可以寫'null'來用default group)
DumbJob.class);         //要執(zhí)行的java類
Trigger trigger = TriggerUtils.makeDailyTrigger(8, 30);
trigger.setStartTime(new Date());
trigger.setName("myTrigger");
sched.scheduleJob(jobDetail, trigger);
現(xiàn)在我們定義“DumbJob”類:
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
System.err.println("DumbJob is executing.");
}
}
可以看到我們給調(diào)度器一個(gè)JobDetail實(shí)例,并且,它通過job的類代碼引用這個(gè)job來執(zhí)行。每次調(diào)度器執(zhí)行job時(shí),它會(huì)在調(diào)用job的execute(..)方法之前創(chuàng)建一個(gè)他的實(shí)例。這就帶來了兩個(gè)事實(shí):一、job必須有一個(gè)不帶參數(shù)的構(gòu)造器,二、在job類里定義數(shù)據(jù)成員并沒有意義,因?yàn)樵诿看蝚ob執(zhí)行的時(shí)候他們的值會(huì)被覆蓋掉。
你可能現(xiàn)在想要問“我怎樣給一個(gè)job實(shí)例提供屬性/配置?”和“在幾次執(zhí)行間我怎樣能跟蹤job的狀態(tài)?”這些問題的答案是一樣的:用JobDataMap- JobDetail對(duì)象的一部分。
JobDataMap
JobDataMap能夠支持任何序列化的對(duì)象,當(dāng)job執(zhí)行時(shí),這些對(duì)象能夠在job實(shí)例中可用。JobDataMap實(shí)現(xiàn)了Java Map接口,它有一些附加的方法,這些方法用來儲(chǔ)存和跟蹤簡單類型的數(shù)據(jù)。
如下代碼可以很快地給job增加JobDataMap:
jobDetail.getJobDataMap().put("jobSays", "Hello World!");
jobDetail.getJobDataMap().put("myFloatValue", 3.141f);
jobDetail.getJobDataMap().put("myStateData", new ArrayList());
在job執(zhí)行時(shí),我們可以在job里通過如下代碼得到JobDataMap:
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
String instName = context.getJobDetail().getName();
String instGroup = context.getJobDetail().getGroup();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
ArrayList state = (ArrayList)dataMap.get("myStateData");
state.add(new Date());
System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);
}
}
如果用一個(gè)持久JobStore(在指南JobStore章節(jié)討論),我們就應(yīng)該注意在JobDataMap里放些什么,因?yàn)樵谒锩娴膶?duì)象將會(huì)被序列化,并且這些對(duì)象會(huì)因此產(chǎn)生一些class-versioning問題。明顯的,標(biāo)準(zhǔn)Java類型應(yīng)該是很安全的,但是,任何時(shí)候某人改變了一個(gè)你已經(jīng)序列化的實(shí)例的類的定義時(shí),我們就要注意不能夠破壞兼容性了。在這個(gè)方面的進(jìn)一步信息可以在Java Developer Connection Tech Tip: Serialization In The Real World里找到。我們能把JDBC-JobStore和JobDataMap放到一個(gè)模式里,在那里,只有簡單類型和String型能被儲(chǔ)存在Map里,從而消去任何以后的序列化問題。
Stateful vs. Non-Stateful Jobs
觸發(fā)器也有與它們關(guān)聯(lián)的JobDataMaps。假設(shè)我們有一個(gè)儲(chǔ)存在調(diào)度器里被多個(gè)觸發(fā)器關(guān)聯(lián)的job,然而,對(duì)于每個(gè)獨(dú)立的觸發(fā)器,我想提供給job不同的數(shù)據(jù)輸入,在這個(gè)時(shí)候,JobDataMaps就很有用了。
在job執(zhí)行期間,JobDataMaps能夠在JobExecutionContext里獲得。JobDataMap融合在Trigger和JobDetail類里,JobDataMap里面的值能夠利用key來更新。
以下例子顯示,在job執(zhí)行期間從JobExecutionContext里的JobDataMap得到數(shù)據(jù):
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
String instName = context.getJobDetail().getName();
String instGroup = context.getJobDetail().getGroup();
JobDataMap dataMap = context.getJobDataMap();  // 注意:不同于以前的例子
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
ArrayList state = (ArrayList)dataMap.get("myStateData");
state.add(new Date());
System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);
}
}
StatefulJob
現(xiàn)在,關(guān)于job狀態(tài)數(shù)據(jù)的一些附加要點(diǎn):一個(gè)job實(shí)例能定義為"有狀態(tài)的"或者"無狀態(tài)的"。無狀態(tài)的jobs僅當(dāng)它們?cè)诒患尤氲秸{(diào)度器里時(shí)才存儲(chǔ)JobDataMap。這就意味著,在jobs執(zhí)行期間對(duì)JobDataMap里數(shù)據(jù)的任何改變都會(huì)丟失,下次執(zhí)行時(shí)job將看不到這些數(shù)據(jù)。你可能會(huì)猜到,一個(gè)有狀態(tài)的job就是它的反面例子-它的JobDataMap是在每次執(zhí)行完job后再次儲(chǔ)存的。一個(gè)缺點(diǎn)就是有狀態(tài)的job不能夠并發(fā)執(zhí)行。換句話說,如果job是有狀態(tài)的,一個(gè)觸發(fā)器嘗試觸發(fā)這個(gè)已經(jīng)執(zhí)行了的job時(shí),這個(gè)觸發(fā)器就會(huì)等待直到這次執(zhí)行結(jié)束。
用實(shí)現(xiàn)StatefulJob 接口來標(biāo)記一個(gè)job是有狀態(tài)的。
Job 'Instances'
我們能夠創(chuàng)建一個(gè)單獨(dú)的job類,并且通過創(chuàng)建多個(gè)JobDetails實(shí)例在調(diào)度器里儲(chǔ)存很多它的“實(shí)例定義”,每個(gè)都有它自己的屬性集和JobDataMap ,把它們都加入到調(diào)度器里。
當(dāng)一個(gè)觸發(fā)器觸發(fā)時(shí),與它關(guān)聯(lián)的job就是通過配置在調(diào)度器上的JobFactory 來實(shí)例化的。默認(rèn)的JobFactory 簡單的調(diào)用在job類上的newInstance()方法,你可能想要?jiǎng)?chuàng)建自己的JobFactory實(shí)現(xiàn)來完成一些自己想要的事情,如:擁有應(yīng)用程序的IoC或者DI容器進(jìn)程/初始化job實(shí)例。
job的其他屬性
這兒有一個(gè)其他屬性的總結(jié),這些屬性是通過JobDetail對(duì)象為一個(gè)job實(shí)例定義的。
持久性– 如果一個(gè)job是非持久的,一旦沒有任何可用的觸發(fā)器與它關(guān)聯(lián)時(shí),他就會(huì)自動(dòng)得從調(diào)度器里被刪除。
不穩(wěn)定性-如果一個(gè)job是不穩(wěn)定的,他就不會(huì)在重起Quartz調(diào)度器之間持久化。
請(qǐng)求恢復(fù)– 如果一個(gè)job“請(qǐng)求恢復(fù)”,在調(diào)度器“硬關(guān)閉”(如:該進(jìn)程崩潰,機(jī)器被關(guān)掉)時(shí)這個(gè)job還在執(zhí)行,過后,當(dāng)調(diào)度器再次啟動(dòng)時(shí),他就會(huì)再次執(zhí)行。在這種情況下,JobExecutionContext.isRecovering() 方法將會(huì)返回true.
Job監(jiān)聽器 –一個(gè)job能夠有0個(gè)或者多個(gè)與它關(guān)聯(lián)的監(jiān)聽器。當(dāng)job執(zhí)行時(shí),監(jiān)聽器就會(huì)被通知。在監(jiān)聽器的更多討論請(qǐng)看TriggerListeners & JobListeners
JobExecutionException
最后,我們來看看Job.execute(..)方法的一些細(xì)節(jié)。你能夠從execute方法里拋出的僅有的異常類型就是JobExecutionException。因?yàn)檫@樣,我們應(yīng)該使用try-catch塊包圍整個(gè)execute方法內(nèi)容。我們還應(yīng)該花一些時(shí)間看看JobExecutionException文檔。當(dāng)job執(zhí)行發(fā)生異常時(shí),通過設(shè)置JobExecutionException,可以讓此job再次進(jìn)入調(diào)度器或者今后不再運(yùn)行。
4.更多關(guān)于Triggers
象jobs一樣,triggers也相對(duì)來說很容易。但是,我們還是要理解它的一些特性。Quartz里也有很多類型的trigger提供給我們使用。
Calendars
Quartz Calendar 對(duì)象(不是java.util.Calendar對(duì)象)能夠在trigger儲(chǔ)存在調(diào)度器時(shí)和trigger關(guān)聯(lián)起來。Calendars主要用來在trigger配置時(shí)排除一些時(shí)間。例如,你能夠創(chuàng)建一個(gè)在每個(gè)工作日早上9:30觸發(fā)的trigger,然后為這個(gè)trigger增加一個(gè)排除所有商業(yè)的節(jié)假日的Calendar。
Calendars能夠是任何序列化的對(duì)象,只要這些對(duì)象實(shí)現(xiàn)了Calendar接口:
package org.quartz;
public interface Calendar {
public boolean isTimeIncluded(long timeStamp);
public long getNextIncludedTime(long timeStamp);
}
注意到這些方法的參數(shù)類型是long。這意味著calendars能夠排除毫秒級(jí)的時(shí)間段。大部分地,我們感興趣的是一整天的,所以在Quartz里,有個(gè)實(shí)現(xiàn)類提供了方便:org.quartz.impl.HolidayCalendar
Calendars必須被實(shí)例化并且通過addCalendar(..)方法注冊(cè)到調(diào)度器里。如果你用HolidayCalendar,在實(shí)例它之后,你應(yīng)該用它的addExcludedDate(Date date)方法以便組裝上你想排除的那幾天。一個(gè)calendar實(shí)例能夠被多個(gè)triggers使用:
HolidayCalendar cal = new HolidayCalendar();
cal.addExcludedDate( someDate );
sched.addCalendar("myHolidays", cal, false);
Trigger trigger = TriggerUtils.makeHourlyTrigger(); // 每小時(shí)觸發(fā)
trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date()));  //下一個(gè)小時(shí)開始  trigger.setName("myTrigger1");
trigger.setCalendarName("myHolidays");
// .. schedule job with trigger
Trigger trigger2 = TriggerUtils.makeDailyTrigger(8, 0); // 每天早上8點(diǎn)觸發(fā)
trigger2.setStartTime(new Date()); //立即開始
trigger2.setName("myTrigger2");
trigger2.setCalendarName("myHolidays");
// .. schedule job with trigger2
不觸發(fā)(misfire)指令
觸發(fā)器的另外一個(gè)重要的屬性是“不觸發(fā)指令”。如果一個(gè)持久的觸發(fā)器由于調(diào)度器被關(guān)閉了而沒有找到它的觸發(fā)時(shí)間,那么一個(gè)不觸發(fā)將會(huì)發(fā)生。不同的觸發(fā)器類型有不同的不觸發(fā)指令。默認(rèn)的,他們都用“smart policy”指令-這是一個(gè)基于觸發(fā)器類型和配置的動(dòng)態(tài)行為。當(dāng)調(diào)度器啟動(dòng)時(shí),他將會(huì)搜尋所有沒觸發(fā)的持久化的triggers,然后基于他們各個(gè)配置的不觸發(fā)指令來更新他們。當(dāng)你用Quartz,你應(yīng)該熟悉各個(gè)不觸發(fā)指令,我們?cè)谝韵抡鹿?jié)有一些介紹。給一個(gè)trigger實(shí)例配置不觸發(fā)指令,要用此實(shí)例的setMisfireInstruction(..)方法。
TriggerUtils - Triggers Made Easy
TriggerUtils類(在org.quartz包里)包含了很多方便的工具。能夠幫你創(chuàng)建triggers和datas。用這個(gè)類能夠很容易制造一些trigges,這些triggers能夠在每分鐘,每小時(shí),每周,每個(gè)月等等觸發(fā)。用它也能產(chǎn)生一些接近某個(gè)秒、分鐘、小時(shí)的天-這在設(shè)置trigger的啟動(dòng)時(shí)間很有幫助。
TriggerListeners
最后,triggers有一些注冊(cè)了的監(jiān)聽器,象job一樣。實(shí)現(xiàn)了TriggerListener接口的對(duì)象將接受一個(gè)trigger被觸發(fā)的通知。
5. SimpleTrigger
詳細(xì)介紹一下它的構(gòu)造器:
public SimpleTrigger(String name, //trigger名稱
String group, //trigger的組名
Date startTime, //開始時(shí)間
Date endTime, //結(jié)束時(shí)間
int repeatCount, //重復(fù)次數(shù)
long repeatInterval)//重復(fù)間隔
舉幾個(gè)常用例子:
從現(xiàn)在開始10秒后執(zhí)行一次:
long startTime = System.currentTimeMillis() + 10000L;
SimpleTrigger trigger = new SimpleTrigger("myTrigger",
null,
new Date(startTime),
null,
0,
0L);
立即執(zhí)行,60秒間隔無限制重復(fù):
SimpleTrigger trigger = new SimpleTrigger("myTrigger",
null,
new Date(),
null,
SimpleTrigger.REPEAT_INDEFINITELY,
60L * 1000L);
從現(xiàn)在開始立即執(zhí)行,每10秒重復(fù),直到40秒后:
long endTime = System.currentTimeMillis() + 40000L;
SimpleTrigger trigger = new SimpleTrigger("myTrigger",
"myGroup",
new Date(),
new Date(endTime),
SimpleTrigger.REPEAT_INDEFINITELY,
10L * 1000L);
在2002年3月17號(hào)10:30am觸發(fā),重復(fù)5次(一共6次),30秒間隔:
java.util.Calendar cal = new java.util.GregorianCalendar(2002, cal.MARCH, 17);
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 不觸發(fā)指令
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
6.CronTrigger
構(gòu)造器
CronTrigger(String name, //觸發(fā)器名稱
String group, //觸發(fā)器的組名
String jobName, //job名稱
String jobGroup, //job的組名
Date startTime, //開始時(shí)間
Date endTime, //結(jié)束時(shí)間
String cronExpression, //克隆表達(dá)式
TimeZone timeZone)//時(shí)區(qū)
還有一些其它參數(shù)少一些的構(gòu)造器,參考JavaDoc。通常我們?nèi)缦潞唵蔚厥褂肅ronTrigger;
Trigger trigger = new CronTrigger("trigger1", "group1");//設(shè)置觸發(fā)器名稱和組名
trigger.setCronExpression("0 0 15 * * ?");//設(shè)置克隆表達(dá)式
克隆表達(dá)式
一個(gè)克隆表達(dá)式是一個(gè)由空白間隔6個(gè)或者7個(gè)字段的字符串。
格式:
字段名
必須有
值范圍
允許的特殊字符
Seconds
YES
0-59
, - * /
Minutes
YES
0-59
, - * /
Hours
YES
0-23
, - * /
Day of month
YES
1-31
, - * ? / L W C
Month
YES
1-12 or JAN-DEC
, - * /
Day of week
YES
1-7 or SUN-SAT
, - * ? / L C #
Year
NO
empty, 1970-2099
, - * /
例子:
* * * * ? *
0 0/5 14,18,3-39,52 ? JAN,MAR,SEP MON-FRI 2002-2010
特殊字符
* 表示所有值 ;
表示未說明的值,即不關(guān)心它為何值;
- 表示一個(gè)指定的范圍;
, 表示附加一個(gè)可能值;
/ 符號(hào)前表示開始時(shí)間,符號(hào)后表示每次遞增的值;
L ("last") "L" 用在day-of-month字段意思是 "這個(gè)月最后一天";用在 day-of-week字段, 它簡單意思是 "7" or "SAT"。 如果在day-of-week字段里和數(shù)字聯(lián)合使用,它的意思就是 "這個(gè)月的最后一個(gè)星期幾" – 例如: "6L" means "這個(gè)月的最后一個(gè)星期五". 當(dāng)我們用“L”時(shí),不指明一個(gè)列表值或者范圍是很重要的,不然的話,我們會(huì)得到一些意想不到的結(jié)果。
W ("weekday") –只能用在day-of-month字段。用來描敘最接近指定天的工作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近這個(gè)月第15天的工作日”,即如果這個(gè)月第15天是周六,那么觸發(fā)器將會(huì)在這個(gè)月第14天即周五觸發(fā);如果這個(gè)月第15天是周日,那么觸發(fā)器將會(huì)在這個(gè)月第16天即周一觸發(fā);如果這個(gè)月第15天是周二,那么就在觸發(fā)器這天觸發(fā)。注意一點(diǎn):這個(gè)用法只會(huì)在當(dāng)前月計(jì)算值,不會(huì)越過當(dāng)前月。“W”字符僅能在day-of-month指明一天,不能是一個(gè)范圍或列表。
也可以用“LW”來指定這個(gè)月的最后一個(gè)工作日。
# -只能用在day-of-week字段。用來指定這個(gè)月的第幾個(gè)周幾。例:在day-of-week字段用"6#3"指這個(gè)月第3個(gè)周五(6指周五,3指第3個(gè))。如果指定的日期不存在,觸發(fā)器就不會(huì)觸發(fā)。
C ("calendar") – 指和calendar聯(lián)系后計(jì)算過的值。例:在day-of-month 字段用“5C”指在這個(gè)月第5天或之后包括calendar的第一天;在day-of-week字段用“1C”指在這周日或之后包括calendar的第一天。
在MONTH和Day of week字段里對(duì)字母大小寫不敏感。
一些例子
表達(dá)式
意思(觸發(fā)時(shí)刻)
0 0 12 * * ?
每天中午12點(diǎn)
0 15 10 * * ? 2005
在2005年的每天10:25
0 10,44 14 ? 3 WED
在3月里每個(gè)周三的14:10和14:44
0 15 10 ? * 6L 2002-2005
從2002年到2005年里,每個(gè)月的最后一個(gè)星期五的10:15
0 0 12 1/5 * ?
從當(dāng)月的第一天開始,然后在每個(gè)月每隔5天的12:00
0 15 10 ? * 6#3
每個(gè)月第3個(gè)周五的10:15
注意在day-of-week和day-of-month字段里使用“?”和“*”的效果。
注意
對(duì)“C”的支持并不很完全。
對(duì)在day-of-week字段 和在day-of-month字段同時(shí)使用也不是很完全(目前你必須在這兩個(gè)字段中的一個(gè)用“?”指定)。
當(dāng)設(shè)置在午夜和凌晨1點(diǎn)之間觸發(fā)時(shí)要仔細(xì)。
不觸發(fā)指令:
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
MISFIRE_INSTRUCTION_DO_NOTHING
7.TriggerListeners 和JobListeners
與Trigger相關(guān)的事件有:觸發(fā)器觸發(fā),觸發(fā)器的不觸發(fā)(參考先前章節(jié)),觸發(fā)器完成。
public interface TriggerListener {
public String getName();
public void triggerFired(Trigger trigger, JobExecutionContext context);
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);
public void triggerMisfired(Trigger trigger);
public void triggerComplete(Trigger trigger, JobExecutionContext context,
int triggerInstructionCode);
}
與job相關(guān)的事件有:job準(zhǔn)備執(zhí)行,job執(zhí)行完畢。
public interface JobListener {
public String getName();
public void jobToBeExecuted(JobExecutionContext context);
public void jobExecutionVetoed(JobExecutionContext context);
public void jobWasExecuted(JobExecutionContext context,
JobExecutionException jobException);
}
使用Listeners
創(chuàng)建一個(gè)監(jiān)聽器,就是創(chuàng)建一個(gè)實(shí)現(xiàn)了org.quartz.TriggerListener 和 org.quartz.JobListener接口的對(duì)象。在運(yùn)行的期間用調(diào)度器注冊(cè)監(jiān)聽器,必須要給它提供一個(gè)名字。監(jiān)聽器能夠注冊(cè)成為全局的或者不是全局的,全局監(jiān)聽器接受所有的事件,而非全局的則僅接受指定給triggers/jobs了的事件。
監(jiān)聽器是在運(yùn)行期間被調(diào)度器注冊(cè)的,他們沒有伴隨jobs和triggers儲(chǔ)存在JobStore里。Jobs和triggers僅儲(chǔ)存和它們相關(guān)的監(jiān)聽器的名字。因此,每次程序運(yùn)行時(shí),監(jiān)聽器需要被調(diào)度器再次注冊(cè)。
scheduler.addGlobalJobListener(myJobListener);
scheduler.addJobListener(myJobListener);
監(jiān)聽器在Quartz并不是經(jīng)常使用的。
8.SchedulerListeners
和調(diào)度器相關(guān)的事件有:job/trigger的加入和移出,一些調(diào)度器里的錯(cuò)誤,調(diào)度器關(guān)閉等等。
public interface SchedulerListener {
public void jobScheduled(Trigger trigger);
public void jobUnscheduled(String triggerName, String triggerGroup);
public void triggerFinalized(Trigger trigger);
public void triggersPaused(String triggerName, String triggerGroup);
public void triggersResumed(String triggerName, String triggerGroup);
public void jobsPaused(String jobName, String jobGroup);
public void jobsResumed(String jobName, String jobGroup);
public void schedulerError(String msg, SchedulerException cause);
public void schedulerShutdown();
}
創(chuàng)建和注冊(cè)SchedulerListeners和其他監(jiān)聽器一樣,全局和非全局的沒有區(qū)別。
9.JobStores
JobStore負(fù)責(zé)保存所有配置到調(diào)度器里的工作數(shù)據(jù):jobs,triggers,calendars等等。在用SchedulerFactory得到一個(gè)調(diào)度器的實(shí)例時(shí),我們可以給SchedulerFactory提供一個(gè)屬性文件或者一個(gè)屬性對(duì)象來聲明使用哪個(gè)JobStore。
注意,不要在代碼里使用JobStore的實(shí)例,這些Quartz都做好了。我們要做的就僅僅告訴Quartz(通過配置)用哪個(gè)JobStore,然后就調(diào)用Scheduler接口函數(shù)了。
RAMJobStore
利用內(nèi)存來持久化調(diào)度程序信息。這種作業(yè)存儲(chǔ)類型最容易配置、構(gòu)造和運(yùn)行,但是當(dāng)應(yīng)用程序停止運(yùn)行時(shí),所有調(diào)度信息將被丟失。
在屬性文件里指定:
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
JDBCJobStore
支持的數(shù)據(jù)庫有:Oracle, MySQL, MS SQLServer2000, HSQLDB, PostreSQL and DB2。使用JDBCJobStore,首先要在數(shù)據(jù)庫里建一些Quartz要使用的表。我們可以使用Quartz發(fā)布包里的建表腳本,在docs/dbTables目錄下。如果沒有你所要的數(shù)據(jù)庫類型的腳本,可以在已有的腳本作一些修改。所有這些標(biāo)都是以“QRTZ_”作為前綴的,這個(gè)前綴是可以在屬性文件里更改的。在為多個(gè)調(diào)度器實(shí)例創(chuàng)建多個(gè)系列的表時(shí),用不同的前綴是很有用的。
一旦我們創(chuàng)建了這些表,在配置和觸發(fā)JDBCJobStore之前就要做更多的事情了。我們需要決定應(yīng)用需要哪種類型的事務(wù)處理。如果我們不需要給其他的事務(wù)處理一些調(diào)度命令(增加刪除trigger),我們就可以讓Quartz利用JobStoreTX處理這個(gè)事務(wù)(這用的很多)。
如果我們需要Quartz和其他的事務(wù)處理(在J2EE應(yīng)用服務(wù)器里)一起工作,我們就應(yīng)該用JobStoreCMT-這會(huì)使Quartz讓應(yīng)用服務(wù)器容器管理事務(wù)。
最后一點(diǎn)是從哪個(gè)JDBCJobStore啟動(dòng)數(shù)據(jù)庫能夠得到該數(shù)據(jù)庫的連接。在屬性文件里是用一個(gè)不同的方法來定義數(shù)據(jù)源的。一種是Quartz自己創(chuàng)建和管理數(shù)據(jù)源-提供所有的數(shù)據(jù)庫連接信息;另外一種是利用應(yīng)用服務(wù)器管理的數(shù)據(jù)源,其中Quartz運(yùn)行在這個(gè)應(yīng)用服務(wù)器里-給JDBCJobStore提供數(shù)據(jù)庫的JNDI名稱。
用JDBCJobStore(假設(shè)我們是用的StdSchedulerFactory),我們首先要設(shè)置org.quartz.jobStore.class屬性為org.quartz.impl.jdbcjobstore.JobStoreTX或者org.quartz.impl.jdbcjobstore.JobStoreCMT,這取決于我們的選擇。
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
下一步,我們需要選擇一個(gè)驅(qū)動(dòng)代理。StdJDBCDelegate是一個(gè)用“vanilla”JDBC代碼實(shí)現(xiàn)的代理。如果沒有其他為你數(shù)據(jù)庫指定的代理,就使用這個(gè)。Quartz開發(fā)者們解決的問題都是根據(jù)這個(gè)代理的來實(shí)現(xiàn)的。其他的代理在org.quartz.impl.jdbcjobstore包或者子包里。包括DB2v6Delegate(DB2 version 6 或早期版本使用的),HSQLDBDelegate(HSQLDB使用),MSSQLDelegate(microsoft SQLServer 2000使用),PostgreSQLDelegate(PostgreSQL 7.x使用),WeblogicDelegate(Weblogic的JDBC驅(qū)動(dòng)器使用),OracleDelegate(Oracle 8i and 9i使用)。
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
在下一步,我們要配置表的前綴:
org.quartz.jobStore.tablePrefix = QRTZ_
最后,我們需要設(shè)置用哪個(gè)數(shù)據(jù)源,數(shù)據(jù)源的名稱必須在Quartz屬性里定義好。例如,我們可以給Quartz指定使用“myDS”(在配置屬性里的其他地方定義好了)作為數(shù)據(jù)源的名字。
org.quartz.jobStore.dataSource = myDS
如果調(diào)度器很繁忙(例如,執(zhí)行job的個(gè)數(shù)和線程池的大小一樣),那么我們應(yīng)該設(shè)置數(shù)據(jù)源的連接個(gè)數(shù)在線程池大小+1之上。
org.quartz.jobStore.useProperties這個(gè)屬性能夠設(shè)置為“true”(默認(rèn)為false),用來指示JDBCJobStore:在JobDataMaps里的所有值都應(yīng)該是String,這樣在能作為name-value方式儲(chǔ)存,而不是在BLOB列里以序列化的格式儲(chǔ)存復(fù)雜的對(duì)象。從長遠(yuǎn)看,這樣做會(huì)很安全,因?yàn)槟憧梢员苊鈱⒎荢tring的類序列化到BLOB里的類版本問題。
10.配置,資源使用和調(diào)度器工廠
Quartz是以標(biāo)準(zhǔn)組件的方式組織的,所以,使它運(yùn)行起來,一些組件需要被聯(lián)合起來。
在Quartz能夠工作之前,需要配置的主要組件有:
線程池
作業(yè)儲(chǔ)存
數(shù)據(jù)源(需要的話)
調(diào)度器自己
在運(yùn)行jobs時(shí),線程池為Quartz提供了一系列的線程。在線程池里的線程越多,能夠并行執(zhí)行的jobs就越多。但是,太多的線程會(huì)使系統(tǒng)癱瘓。大部分的Quartz用戶發(fā)現(xiàn),5個(gè)線程就足夠了-因?yàn)樗麄冊(cè)谥付〞r(shí)間里只有少于100的jobs,這些jobs并不都是在同一時(shí)刻執(zhí)行,jobs完成得也很快的。其他的用戶發(fā)現(xiàn)他們需要10、15、50或者100個(gè)線程-因?yàn)樗麄冊(cè)诓煌恼{(diào)度器里用了上萬個(gè)觸發(fā)器,在給定的時(shí)間里,平均在10到100個(gè)jobs試著執(zhí)行。為調(diào)度器找到合適的線程數(shù)量完全依賴于你用調(diào)度起來做什么。不在乎線程數(shù)量,而要確保你有足夠的線程來使jobs執(zhí)行。如果一個(gè)觸發(fā)器的觸發(fā)時(shí)間到來了,可是沒有一個(gè)能夠用的線程,Quartz將會(huì)等到可用線程的來臨,然后job將會(huì)在幾毫秒后執(zhí)行。這可能會(huì)引起不觸發(fā)-如果不在屬性文件里給調(diào)度器配置“misfire threshold”的話。
線程池接口是在org.quartz.spi包里定義的,你能夠創(chuàng)建一個(gè)線程池以自己的方法。Quartz裝配了一個(gè)簡單(但是很好的)的線程池,是org.quartz.simpl.SimpleThreadPool。這個(gè)線程池簡單的維護(hù)一些在池里固定的線程-不會(huì)增加也不會(huì)減少。但是它能夠做很多事而且經(jīng)過測試了的,幾乎每個(gè)Quartz用戶用這個(gè)線程池。
JobStores 和 DataSrouces在前面討論過了,這里值得一提的是,所有JobStores都實(shí)現(xiàn)了org.quartz.spi.JobStore接口,如果在打包里的任何一個(gè)JobStore不能夠滿足你的需求的話,你可以自己做一個(gè)。
最后,你需要?jiǎng)?chuàng)建你的Scheduler實(shí)例。Scheduler需要提供他的名稱,說明RMI的設(shè)置,處理JobStore和ThreadPool的實(shí)例。RMI設(shè)置包括調(diào)度器是否作為一個(gè)RMI服務(wù)器而創(chuàng)建。StdSchedulerFactory也能夠產(chǎn)生調(diào)度器的實(shí)例,這些實(shí)例實(shí)際上是創(chuàng)建在遠(yuǎn)程進(jìn)程中的調(diào)度器代理(RMI樁)。
StdSchedulerFactory
StdSchedulerFactory實(shí)現(xiàn)了org.quartz.SchedulerFactory接口。它用了一系列的屬性(java.util.Properties)來創(chuàng)建和初始化一個(gè)Quartz的調(diào)度器。這些屬性通常保存和加載在一個(gè)文件里,但是也可以通過你的程序創(chuàng)建直接交給工廠處理。在工廠上調(diào)用getScheduler()就可以產(chǎn)生調(diào)度器,初始化它(還有線程池,JobStore和數(shù)據(jù)源),然后返回一個(gè)句柄到這個(gè)公共的接口。
// 默認(rèn)調(diào)度器是quartz.propeties文件定義的,這個(gè)文件可以在當(dāng)前目錄下找到,也可以在//classpath里找到,如果都找不到了,就用quartz.jar里的quartz.propeties文件。
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = sf.getScheduler();
scheduler.start();
用指定的屬性對(duì)象初始化:
SchedulerFactory sf = new StdSchedulerFactory();
sf.initialize(schedulerProperties);// schedulerProperties是屬性對(duì)象
Scheduler scheduler = sf.getScheduler();
scheduler.start();
用指定的屬性文件初始化:
SchedulerFactory sf = new StdSchedulerFactory();
sf.initialize(fileName);//屬性文件全名
Scheduler scheduler = sf.getScheduler();
scheduler.start();
DirectSchedulerFactory
DirectSchedulerFactory是另外的一個(gè)SchedulerFactory實(shí)現(xiàn)。在更多的編程方法里創(chuàng)建調(diào)度器時(shí),他很有用。他的用法不被贊成,原因有:1.它需要用戶更清楚的知道他們?cè)谧鍪裁础?.它不允許配置,就是說,你必須要在代碼里配置所有的調(diào)度器屬性。
Logging
Quartz給它所有需要的日志是使用org.apache.commons.logging框架的。Quartz沒有產(chǎn)生很多的日志信息。僅有一些在初始化時(shí)關(guān)于一些jobs正在執(zhí)行的問題的信息。為了調(diào)整日志設(shè)置,我們需要了解Jakarta Commons Logging框架,超過了本文檔討論的范圍。
11.高級(jí)(企業(yè))特性
集群
目前集群僅以JDBC-Jobstore (JobStoreTX or JobStoreCMT)工作。這些特性包含load-balancing和任務(wù)fail-over(如果JobDetail的"request recovery"標(biāo)志設(shè)為true的話)。
通過設(shè)置org.quartz.jobStore.isClustered屬性為“true”來使用集群。在集群里的每個(gè)調(diào)度器實(shí)例應(yīng)該用一樣的quartz.properties文件。集群會(huì)有如下異常:線程池大小不同,屬性org.quartz.scheduler.instanceName值不同。其實(shí)在集群的每個(gè)節(jié)點(diǎn)都有一個(gè)唯一的實(shí)例ID,要達(dá)到這樣也很簡單,也不需要不同的屬性文件,只要將屬性org.quartz.scheduler.instanceId的值設(shè)置為“AUTO”。
不要在一個(gè)分離開的機(jī)器上運(yùn)行集群,除非他們的時(shí)鐘是用時(shí)鐘同步服務(wù)同步過的。如果不熟悉怎樣同步,參考:http://www.boulder.nist.gov/timefreq/service/its.htm
其他調(diào)度器實(shí)例在用數(shù)據(jù)表時(shí),不要觸發(fā)一個(gè)也用到這些數(shù)據(jù)表的不是集群的調(diào)度器實(shí)例。你會(huì)得到一些沒用的數(shù)據(jù)。
JTA 事務(wù)
在第9節(jié)解釋過JobStores,JobStoreCMT允許Quartz調(diào)度一些具有很大JTA事務(wù)的操作。
通過設(shè)置“org.quartz.scheduler.wrapJobExecutionInUserTransaction”屬性為true,Jobs也能夠在一個(gè)JTA事務(wù)里執(zhí)行。有了這個(gè)設(shè)置,一個(gè)JTA事務(wù)會(huì)在job的execute()方法調(diào)用前開始(begin),然后在調(diào)用execute()方法結(jié)束后提交(commit)。
除了在JTA事務(wù)里Quartz自動(dòng)地和job的執(zhí)行掛鉤之外,當(dāng)使用JobStoreCMT時(shí)也可以調(diào)用你在調(diào)度器接口里的實(shí)現(xiàn)的方法,確保你在調(diào)用一個(gè)調(diào)度器上的方法之前開始了事務(wù)。你也可以直接自己做,使用UserTransaction,或者把用了調(diào)度器的代碼放在一個(gè)使用容器的SessionBean里來管理事務(wù)。
12. Quartz 的其他特性
Plug-Ins
Quartz 提供了一個(gè)接口(org.quartz.spi.SchedulerPlugin) 來實(shí)現(xiàn)plugging-in 的功能。
裝配給Quartz的Plugins能提供不同的有用的功能。在org.quartz.plugins包里有詳細(xì)說明。他們提供的功能例如:調(diào)度器啟動(dòng)時(shí)自動(dòng)調(diào)度jobs,記錄job和triggers事件的歷史,當(dāng)JVM退出時(shí)確保調(diào)度器關(guān)閉。
可以通過配置屬性文件來使用自己實(shí)現(xiàn)或Quartz自帶的插件。
JobFactory
當(dāng)一個(gè)trigger觸發(fā)時(shí),通過一個(gè)配置到調(diào)度器上的JobFactory,與trigger相關(guān)的job就被實(shí)例化了。默認(rèn)的JobFactory會(huì)在job類上調(diào)用newInstance(),你可能想要?jiǎng)?chuàng)建自己的JobFactory實(shí)現(xiàn)來完成一些其他的事情,如:擁有應(yīng)用程序的IoC或者DI容器進(jìn)程/初始化job實(shí)例。
與Scheduler.setJobFactory(fact)方法聯(lián)合起來察看org.quartz.spi.JobFactory接口,
Jobs工具
Quartz也提供一些有用的job,你能夠用這些job來發(fā)郵件或者調(diào)用EJB。我們能在org.quartz.jobs包里找到它們。
13.配置文件里配置項(xiàng)總結(jié)
設(shè)置主要調(diào)度器
屬性名
必須
類型
缺省值
org.quartz.scheduler.instanceName
no
string
'QuartzScheduler'
org.quartz.scheduler.instanceId
no
string
'NON_CLUSTERED'
org.quartz.scheduler.threadName
no
string
instanceName + '_QuartzSchedulerThread'
org.quartz.scheduler.idleWaitTime
no
long
30000
org.quartz.scheduler.dbFailureRetryInterval
no
long
15000
org.quartz.scheduler.classLoadHelper.class
no
string (class name)
org.quartz.simpl.CascadingClassLoadHelper
org.quartz.context.key.SOME_KEY
no
string
none
org.quartz.scheduler.userTransactionURL
no
string (url)
'java:comp/UserTransaction'
org.quartz.scheduler.wrapJobExecutionInUserTransaction
no
booelan
false
org.quartz.scheduler.jobFactory.class
no
string (class name)
org.quartz.simpl.SimpleJobFactory
org.quartz.scheduler.instanceName
任意的String,對(duì)于調(diào)度器自己并沒有意義。但是當(dāng)多個(gè)調(diào)度器實(shí)例用在一個(gè)程序里時(shí),他就可以用來為客戶端代碼區(qū)別每個(gè)調(diào)度器。如果你用集群這個(gè)特性,你必須為在集群里的每個(gè)實(shí)例用一樣的名字,實(shí)現(xiàn)邏輯上的一樣的調(diào)度器。
org.quartz.scheduler.instanceId
任意的String,如果在一個(gè)集群里多個(gè)實(shí)例是一個(gè)邏輯上一樣的調(diào)度器時(shí),每個(gè)實(shí)例的這項(xiàng)屬性必須唯一。你可以設(shè)置這項(xiàng)為“AUTO”從而自動(dòng)收集ID。
org.quartz.scheduler.idleWaitTime
當(dāng)調(diào)度器空閑時(shí),在再次查詢可用triggers之前,調(diào)度器將要等等待的毫秒數(shù)。正常情況下,我們不調(diào)整這個(gè)參數(shù),除非我們用XA事務(wù),或者在立即觸發(fā)trigger時(shí)結(jié)果延誤了。
org.quartz.scheduler.classLoadHelper.class
不需要更改。
org.quartz.context.key.SOME_KEY
設(shè)置org.quartz.context.key.MyKey = MyValue等價(jià)于scheduler.getContext().put("MyKey", "MyValue")
org.quartz.scheduler.userTransactionURL
是一個(gè)JNDI URL,Quartz用它來定位應(yīng)用服務(wù)器的UserTransaction管理器。Websphere用戶可能需要設(shè)置它為“jta/usertransaction”。在Quartz配置用到JobStoreCMT時(shí)并且屬性org.quartz.scheduler.wrapJobExecutionInUserTransaction設(shè)置為true時(shí)才有用。
org.quartz.scheduler.wrapJobExecutionInUserTransaction
設(shè)置這項(xiàng)為true使我們?cè)谡{(diào)用job的execute()之前能夠開始一個(gè)UserTransaction。在job的execute()完成之后,事務(wù)將會(huì)提交,并且,JobDataMap也更新了(是有狀態(tài)的job)。
設(shè)置線程池
屬性名
必須
類型
缺省值
org.quartz.threadPool.class
yes
string (clas name)
null
org.quartz.threadPool.threadCount
yes
int
-1
org.quartz.threadPool.threadPriority
no
int
Thread.NORM_PRIORITY (5)
org.quartz.threadPool.makeThreadsDaemons
no
boolean
false
org.quartz.threadPool.threadsInheritGroupOfInitializingThread
no
boolean
true
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread
no
boolean
false
org.quartz.threadPool.class
通常使用org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadPriority
在 Thread.MIN_PRIORITY (1) 和Thread.MAX_PRIORITY (10)之間
org.quartz.threadPool.makeThreadsDaemons、org.quartz.threadPool.threadsInheritGroupOfInitializingThread 和org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread 三個(gè)屬性是指定的SimpleThreadPool的屬性。
如果用自己實(shí)現(xiàn)的線程池,可如下配置:
org.quartz.threadPool.class = com.mycompany.goo.FooThreadPool
org.quartz.threadPool.somePropOfFooThreadPool = someValue
設(shè)置全局監(jiān)聽器
全局監(jiān)聽器要有一個(gè)無參數(shù)的構(gòu)造器,它的屬性是通過反射設(shè)置的,僅支持簡單數(shù)據(jù)和String。
Trigger監(jiān)聽器:
org.quartz.triggerListener.NAME.class = com.foo.MyListenerClass
org.quartz.triggerListener.NAME.propName = propValue
org.quartz.triggerListener.NAME.prop2Name = prop2Value
job監(jiān)聽器:
org.quartz.jobListener.NAME.class = com.foo.MyListenerClass
org.quartz.jobListener.NAME.propName = propValue
org.quartz.jobListener.NAME.prop2Name = prop2Value
設(shè)置Plugins
配置自己的插件(和全局監(jiān)聽器差不多):
org.quartz.plugin.NAME.class = com.foo.MyPluginClass
org.quartz.plugin.NAME.propName = propValue
org.quartz.plugin.NAME.prop2Name = prop2Value
也可以配置Quartz實(shí)現(xiàn)的插件:
1.trigger歷史日志記錄插件(屬性配置中的{數(shù)字}參考JavaDoc):
org.quartz.plugin.triggHistory.class=org.quartz.plugins.history.LoggingTriggerHistoryPlugin
org.quartz.plugin.triggHistory.triggerFiredMessage=
Trigger {1}.{0} fired job {6}.{5} at:{4, date, HH:mm:ss MM/dd/yyyy}
org.quartz.plugin.triggHistory.triggerCompleteMessage =
Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy}
2.從XML文件中初始化job的插件(屬性配置中的文件名是加載jobs用到的xml文件,這個(gè)文件必須在classPath里):
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
org.quartz.plugin.jobInitializer.fileName =data/my_job_data.xml
org.quartz.plugin.jobInitializer.overWriteExistingJobs = false
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
在上例中,JobInitializationPlugin只支持一個(gè)xml文件的初始化,Quartz還提供多個(gè)xml文件的初始化,用JobInitializationPluginMultiple,文件名用“,”隔開。
含有多個(gè)Jobs的一個(gè)xml文件的一個(gè)例子:
<?xml version='1.0' encoding='utf-8'?>
<quartz xmlns="
xmlns:xsi="
xsi:schemaLocation="http://www.opensymphony.com/quartz/JobSchedulingData
version="1.5">
<calendar class-name="org.quartz.impl.calendar.HolidayCalendar" replace="true">
<name>holidayCalendar</name>
<description>HolidayCalendar</description>
<base-calendar class-name="org.quartz.impl.calendar.WeeklyCalendar">
<name>weeklyCalendar</name>
<description>WeeklyCalendar</description>
<base-calendar class-name="org.quartz.impl.calendar.AnnualCalendar">
<name>annualCalendar</name>
<description>AnnualCalendar</description>
</base-calendar>
</base-calendar>
</calendar>
<job>
<job-detail>
<name>testJob1</name>
<group>testJobs</group>
<description>Test Job Number 1</description>
<job-class>personal.ruanyang.quartz.plugin.SimpleJob</job-class>
<volatility>false</volatility>
<durability>false</durability>
<recover>false</recover>
<job-data-map allows-transient-data="true">
<entry>
<key>test1</key>
<value>test1</value>
</entry>
<entry>
<key>test2</key>
<value>test2</value>
</entry>
</job-data-map>
</job-detail>
<trigger>
<cron>
<name>testTrigger1</name>
<group>testJobs</group>
<description>Test Trigger Number 1</description>
<job-name>testJob1</job-name>
<job-group>testJobs</job-group>
<!--
<start-time>2003-12-17 2:15:00 pm</start-time>
<end-time>2013-12-17 2:15:00 pm</end-time>
-->
<cron-expression>0/15 * * ? * *</cron-expression>
<!-- every 15 seconds... -->
</cron>
</trigger>
</job>
<job>
<job-detail>
<name>testJob2</name>
<group>testJobs</group>
<description>Test Job Number 2</description>
<job-class>personal.ruanyang.quartz.plugin.SimpleJob</job-class>
<volatility>false</volatility>
<durability>false</durability>
<recover>false</recover>
</job-detail>
<trigger>
<simple>
<name>testTrigger2</name>
<group>testJobs</group>
<description>Test Trigger Number 2</description>
<calendar-name>holidayCalendar</calendar-name>
<job-name>testJob2</job-name>
<job-group>testJobs</job-group>
<start-time>2004-02-26T12:26:00</start-time>
<repeat-count>10</repeat-count>
<repeat-interval>5000</repeat-interval>
</simple>
</trigger>
</job>
</quartz>
3.Shutdown Hook(通過捕捉JVM關(guān)閉時(shí)的事件,來關(guān)閉調(diào)度器)插件:
org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin
org.quartz.plugin.shutdownhook.cleanShutdown = true
設(shè)置RMI
RMI Server Scheduler Properties
沒有必需的主要屬性,所有的都是合理的缺省的。通過RMI使用Quartz時(shí),我們需要啟動(dòng)一個(gè)配置好了的Quartz實(shí)例來通過RMI“輸出”它的服務(wù)。然后我們通過配置Quartz的調(diào)度器創(chuàng)建一個(gè)客戶端來“代理”它連到服務(wù)器上的工作。
一些用戶在客戶端和服務(wù)器端經(jīng)歷過類可用性(jobs classes)的問題,為了解決這些問題,我們需要理解RMI的“codebase”和RMI的安全管理。以下資源在這方面會(huì)很有用:
RMI和codebase的精彩描敘:
http://www.kedwards.com/jini/codebase.html  重要的一點(diǎn)要意識(shí)到,codebase是被客戶端使用的。
安全管理的快速信息:http://gethelp.devx.com/techtips/java_pro/10MinuteSolutions/10min0500.asp
最后讀來自于java API文檔的RMISecurityManager:
http://java.sun.com/j2se/1.4.2/docs/api/java/rmi/RMISecurityManager.html
屬性名
需要
缺省值
org.quartz.scheduler.rmi.export
no
false
org.quartz.scheduler.rmi.registryHost
no
'localhost'
org.quartz.scheduler.rmi.registryPort
no
1099
org.quartz.scheduler.rmi.createRegistry
no
'never'
org.quartz.scheduler.rmi.serverPort
no
random
org.quartz.scheduler.rmi.proxy
no
false
org.quartz.scheduler.rmi.export
如果我們想要Quartz調(diào)度器通過RMI輸出服務(wù),那么我們就把“rmi.export”標(biāo)志執(zhí)為true。
org.quartz.scheduler.rmi.registryHost
能夠找到的RMI注冊(cè)的主機(jī)(常為“localhost”)。
org.quartz.scheduler.rmi.registryPort
RMI注冊(cè)的監(jiān)聽端口(常為1099).
org.quartz.scheduler.rmi.createRegistry
設(shè)置“rmi.createRegistry” 依照我們想要Quartz怎樣創(chuàng)建RMI注冊(cè)。如果我們不想Quartz創(chuàng)建一個(gè)注冊(cè),就可以用“false”或“never”(如已經(jīng)有了一個(gè)外部的注冊(cè)在運(yùn)行了)。如果我們想先要Quartz嘗試使用一個(gè)存在的注冊(cè)并且然后返回再建一個(gè),就用“true”或者“as_needed”。如果我們想要Quartz嘗試創(chuàng)建一個(gè)注冊(cè)然后返回使用一個(gè)存在的,就用“always”。如果注冊(cè)被創(chuàng)建,它將會(huì)綁定屬性“org.quartz.scheduler.rmi.registryPort”提供的端口,“org.quartz.rmi.registryHost”應(yīng)該是主機(jī)。
org.quartz.scheduler.rmi.serverPort
Quartz調(diào)度器服務(wù)將綁定和監(jiān)聽連接的端口。缺省的,RMI服務(wù)將隨機(jī)選擇一個(gè)端口。
org.quartz.scheduler.rmi.proxy
如果想要連接到遠(yuǎn)程的調(diào)度器服務(wù),我們就要設(shè)置“org.quartz.scheduler.rmi.proxy”為true。然后必需指定一個(gè)主機(jī)和它注冊(cè)了的端口號(hào)。
在同一個(gè)文件里給“org.quartz.scheduler.rmi.export”和“org.quartz.scheduler.rmi.proxy”同時(shí)設(shè)置為true并沒有意義。如果你這樣做的話,“export”項(xiàng)會(huì)被忽略。如果你沒有通過RMI用Quartz,給這兩項(xiàng)同時(shí)設(shè)置為false當(dāng)然也沒有用。
設(shè)置RAMJobStore
RAMJobStore用來在內(nèi)存里儲(chǔ)存調(diào)度時(shí)的信息(job,trigger,calendars)。RAMJobStore很快并且是輕量級(jí)的,但是當(dāng)進(jìn)程終止時(shí)所有的信息都將丟失。
通過設(shè)置“org.quartz.jobStore.class”屬性來選用RAMJobStore:
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
RAMJobStore 能夠通過下面的屬性來調(diào)整:
屬性名
需要
類型
缺省值
org.quartz.jobStore.misfireThreshold
no
int
60000
org.quartz.jobStore.misfireThreshold
在觸發(fā)器被認(rèn)為沒有觸發(fā)之前,調(diào)度器能承受一個(gè)觸發(fā)器再次觸發(fā)的一個(gè)毫秒級(jí)數(shù)字。
設(shè)置JDBC-JobStoreTX
JobStoreTX是在每次行為(如增加一個(gè)job)之后,通過調(diào)用commit() (或者 rollback())來管理事務(wù)。如果你在一個(gè)單機(jī)應(yīng)用里或者當(dāng)在一個(gè)servlet容器里用Quartz而且應(yīng)用沒有用JTA事務(wù)時(shí),JDBCJobStore是正確的。
JobStoreTX是通過設(shè)置“org.quartz.jobStore.class”屬性來選用的:
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
JobStoreTX能夠通過以下屬性來調(diào)整:
屬性名
必須
類型
缺省值
org.quartz.jobStore.driverDelegateClass
yes
string
null
org.quartz.jobStore.dataSource
yes
string
null
org.quartz.jobStore.tablePrefix
no
string
"QRTZ_"
org.quartz.jobStore.useProperties
no
boolean
false
org.quartz.jobStore.misfireThreshold
no
int
60000
org.quartz.jobStore.isClustered
no
boolean
false
org.quartz.jobStore.clusterCheckinInterval
no
long
15000
org.quartz.jobStore.maxMisfiresToHandleAtATime
no
int
20
org.quartz.jobStore.dontSetAutoCommitFalse
no
boolean
false
org.quartz.jobStore.selectWithLockSQL
no
string
"SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE"
org.quartz.jobStore.txIsolationLevelSerializable
no
boolean
false
org.quartz.jobStore.driverDelegateClass
org.quartz.impl.jdbcjobstore.StdJDBCDelegate (所有JDBC兼容的驅(qū)動(dòng))
org.quartz.impl.jdbcjobstore.MSSQLDelegate (Microsoft SQL Server和Sybase)
org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.impl.jdbcjobstore.WebLogicDelegate (WebLogic驅(qū)動(dòng))
org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.impl.jdbcjobstore.oracle.WebLogicOracleDelegate (用在Weblogic里的Oracle驅(qū)動(dòng))
org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate (用在Weblogic里的Oracle驅(qū)動(dòng))
org.quartz.impl.jdbcjobstore.CloudscapeDelegate
org.quartz.impl.jdbcjobstore.DB2v6Delegate
org.quartz.impl.jdbcjobstore.DB2v7Delegate
org.quartz.impl.jdbcjobstore.HSQLDBDelegate
org.quartz.impl.jdbcjobstore.PointbaseDelegate
org.quartz.jobStore.misfireThreshold
同RAM
org.quartz.jobStore.clusterCheckinInterval
影響著核查出失敗實(shí)例的速度。
org.quartz.jobStore.dontSetAutoCommitFalse
設(shè)置這個(gè)屬性為“true”是讓Quartz不去在JDBC連接上調(diào)用setAutoCommit(false)這個(gè)函數(shù)。
org.quartz.jobStore.selectWithLockSQL
在“LOCKS”表里選擇一行并且鎖住這行的SQL語句。缺省的語句能夠?yàn)榇蟛糠謹(jǐn)?shù)據(jù)庫工作。“{0}”是在運(yùn)行時(shí)你配置的表前綴。
org.quartz.jobStore.txIsolationLevelSerializable
設(shè)置“true”讓Quartz(當(dāng)用JobStoreTX或CMT)在JDBC連接上調(diào)用setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE)。這可以阻止數(shù)據(jù)庫在高加載或長時(shí)間的事務(wù)情況下的鎖超時(shí)。
設(shè)置JDBC-JobStoreCMT
JobStoreCMT是依賴與被用Quartz的應(yīng)用管理著的事務(wù)。JTA事務(wù)必須在嘗試調(diào)度(或卸載調(diào)度)jobs/triggers之前處在進(jìn)程中。這允許調(diào)度工作成為應(yīng)用加大事務(wù)的一部分。JobStoreCMT實(shí)際上需要用到兩個(gè)數(shù)據(jù)源,一個(gè)數(shù)據(jù)源要連到被應(yīng)用服務(wù)器管理的事務(wù)(通過JTA),另外一個(gè)數(shù)據(jù)源的連接在全局(JTA)事務(wù)中并不參加。當(dāng)應(yīng)用用JTA事務(wù)(例如通過EJB Session Beans)來執(zhí)行他們的工作時(shí),JobStoreCMT是正確的。
通過設(shè)置 'org.quartz.jobStore.class'屬性來選用JobStore:
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT
JobStoreCMT通過以下屬性來調(diào)整:
屬性名
必須
類型
缺省值
org.quartz.jobStore.driverDelegateClass
yes
string
null
org.quartz.jobStore.dataSource
yes
string
null
org.quartz.jobStore.nonManagedTXDataSource
yes
string
null
org.quartz.jobStore.tablePrefix
no
string
"QRTZ_"
org.quartz.jobStore.useProperties
no
boolean
false
org.quartz.jobStore.misfireThreshold
no
int
60000
org.quartz.jobStore.isClustered
no
boolean
false
org.quartz.jobStore.clusterCheckinInterval
no
long
15000
org.quartz.jobStore.maxMisfiresToHandleAtATime
no
int
20
org.quartz.jobStore.dontSetAutoCommitFalse
no
boolean
false
org.quartz.jobStore.dontSetNonManagedTXConnectionAutoCommitFalse
no
boolean
false
org.quartz.jobStore.selectWithLockSQL
no
string
"SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE"
org.quartz.jobStore.txIsolationLevelSerializable
no
boolean
false
org.quartz.jobStore.txIsolationLevelReadCommitted
no
boolean
false
org.quartz.jobStore.dataSource
對(duì)于JobStoreCMT,數(shù)據(jù)源需要包含能夠加入JTA(容器管理)事務(wù)里的連接。這就意味著數(shù)據(jù)源將在應(yīng)用服務(wù)器里被配置和管理,并且,Quartz將通過JNDI獲得一個(gè)句柄。
org.quartz.jobStore.nonManagedTXDataSource
JobStoreCMT需要一個(gè)數(shù)據(jù)源(以上說的第二個(gè))連到不是容器管理的事務(wù)。這個(gè)值將是定義在配置屬性文件的一個(gè)數(shù)據(jù)源名稱,這個(gè)數(shù)據(jù)源必須包含非CMT的連接,換句話說,就是Quartz直接在連接上調(diào)用commit()和rollback()。
org.quartz.jobStore.dontSetNonManagedTXConnectionAutoCommitFalse
除了它應(yīng)用于非TX數(shù)據(jù)源管理,其他的和org.quartz.jobStore.dontSetAutoCommitFalse一樣
org.quartz.jobStore.txIsolationLevelReadCommitted
設(shè)置“true”,讓Quartz在沒有被管理的JDBC連接上調(diào)用setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED)。這可以阻止一些數(shù)據(jù)庫(如DB2)在高加載和長時(shí)間事務(wù)的情況下發(fā)生的鎖超時(shí)。
設(shè)置數(shù)據(jù)源
如果你用JDBC-JobStore,你將需要一個(gè)數(shù)據(jù)源(或在JobStoreCMT里要2個(gè))。
數(shù)據(jù)源能通過2種方法配置:
Quartz搜集所有指定在quartz.properties 文件里的屬性來創(chuàng)建數(shù)據(jù)源。
指定一個(gè)定位于管理數(shù)據(jù)源的應(yīng)用服務(wù)器的JNDI,這樣Quartz能用它。
每個(gè)定義的數(shù)據(jù)源必須有個(gè)名字,你為這個(gè)數(shù)據(jù)源定義的一些屬性必須包含這個(gè)名字,象下面的。數(shù)據(jù)源的“NAME”可以隨便取,只有當(dāng)我們把數(shù)據(jù)源賦給JDBCJobStore時(shí),這個(gè)名字起到標(biāo)示的作用,其他情況下沒什么用。
Quartz自己創(chuàng)建數(shù)據(jù)源通過以下屬性:
屬性名
必須
類型
缺省值
org.quartz.dataSource.NAME.driver
yes
String
null
org.quartz.dataSource.NAME.URL
yes
String
null
org.quartz.dataSource.NAME.user
no
String
""
org.quartz.dataSource.NAME.password
no
String
""
org.quartz.dataSource.NAME.maxConnections
no
int
10
org.quartz.dataSource.NAME.validationQuery
no
String
null
org.quartz.dataSource.NAME.validationQuery
是一個(gè)可選的SQL查詢字符串,數(shù)據(jù)源用它來核查和替代失敗/被破壞的連接。例如,一個(gè)Oracle用戶可能選擇“select table_name from user_tables”-這是一個(gè)決不可能失敗的查詢,除非連接是壞的。
org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@10.0.1.23:1521:demodb
org.quartz.dataSource.myDS.user = myUser
org.quartz.dataSource.myDS.password = myPassword
org.quartz.dataSource.myDS.maxConnections = 30
引用應(yīng)用服務(wù)器的數(shù)據(jù)源:
屬性值
必須
類型
缺省值
org.quartz.dataSource.NAME.jndiURL
yes
String
null
org.quartz.dataSource.NAME.java.naming.factory.initial
no
String
null
org.quartz.dataSource.NAME.java.naming.provider.url
no
String
null
org.quartz.dataSource.NAME.java.naming.security.principal
no
String
null
org.quartz.dataSource.NAME.java.naming.security.credentials
no
String
null
org.quartz.dataSource.NAME.java.naming.factory.initial
JNDI上下文初始化工廠的類名。
org.quartz.dataSource.NAME.java.naming.provider.url
連接到JNDI上下文的URL。
org.quartz.dataSource.NAME.java.naming.security.principal
連接到JNDI上下文的首要用戶。
org.quartz.dataSource.NAME.java.naming.security.credentials
連接到JNDI上下文的用戶驗(yàn)證密碼。
org.quartz.dataSource.myOtherDS.jndiURL=jdbc/myDataSource
org.quartz.dataSource.myOtherDS.java.naming.factory.initial=
com.evermind.server.rmi.RMIInitialContextFactory
org.quartz.dataSource.myOtherDS.java.naming.provider.url=ormi://localhost
org.quartz.dataSource.myOtherDS.java.naming.security.principal=admin
org.quartz.dataSource.myOtherDS.java.naming.security.credentials=123
設(shè)置集群
集群可以通過fail-over和load balancing功能給調(diào)度器帶來既高可靠性又可伸縮性兩大優(yōu)點(diǎn)。
集群目前僅能和JDBC-JobStore(JobStoreTX或JobStoreCMT)一起工作,本質(zhì)上是讓集群的每個(gè)節(jié)點(diǎn)共享一個(gè)數(shù)據(jù)庫來工作的。
Load-balancing是自動(dòng)出現(xiàn)的,集群的每個(gè)節(jié)點(diǎn)盡可能快地觸發(fā)job。當(dāng)一個(gè)觸發(fā)器觸發(fā)時(shí)刻到了,第一個(gè)將獲取觸發(fā)器(并加鎖)的節(jié)點(diǎn)就是將要觸發(fā)它的節(jié)點(diǎn)。
Fail-over是一個(gè)節(jié)點(diǎn)正在執(zhí)行一個(gè)或多個(gè)jobs時(shí)失敗了出現(xiàn)的。當(dāng)一個(gè)節(jié)點(diǎn)失敗了,其他的節(jié)點(diǎn)就會(huì)在數(shù)據(jù)庫里核查條件和鑒別jobs,這些是節(jié)點(diǎn)失敗時(shí)記錄到了數(shù)據(jù)庫的。在恢復(fù)節(jié)點(diǎn)時(shí),任何標(biāo)記了恢復(fù)(JobDetail里的"requests recovery"屬性)的jobs將會(huì)被再次執(zhí)行,沒有標(biāo)記的將會(huì)簡單地釋放掉。
通過設(shè)置“org.quartz.jobStore.isClustered”屬性來使用集群。在集群里每個(gè)實(shí)例應(yīng)該用一樣的quartz.properties文件。用到的異常也應(yīng)該是一樣的:不同線程池大小,不同“org.quartz.scheduler.instanceName”屬性值。每個(gè)節(jié)點(diǎn)應(yīng)該用唯一的instanceId。我們可以設(shè)置org.quartz.scheduler.instanceId的值為“AUTO”來達(dá)到這個(gè)目的。
不要在一個(gè)分離開的機(jī)器上運(yùn)行集群,除非他們的時(shí)鐘是用時(shí)鐘同步服務(wù)同步過的。如果不熟悉怎樣同步,參考:http://www.boulder.nist.gov/timefreq/service/its.htm
其他實(shí)例在用數(shù)據(jù)表時(shí),不要觸發(fā)一個(gè)不是集群的也用這些數(shù)據(jù)表的實(shí)例。你會(huì)得到一些沒用的數(shù)據(jù)。
#=================================================================# Configure Main Scheduler Properties
#=================================================================org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
#=================================================================# Configure ThreadPool
#=================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5
#=================================================================# Configure JobStore
#=================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
#=================================================================
# Configure Datasources
#=================================================================
org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@polarbear:1521:dev
org.quartz.dataSource.myDS.user = quartz
org.quartz.dataSource.myDS.password = quartz
org.quartz.dataSource.myDS.maxConnections = 5
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
14.在Web應(yīng)用中用Quartz
初始化調(diào)度器
我們可以在Web應(yīng)用中的配置文件web.xml里設(shè)置一個(gè)Quartz的Servlet-QuartzInitializerServlet:
<web-app>
<servlet>
<servlet-name>QuartzInitializer</servlet-name>   <display-name>Quartz Initializer Servlet</display-name> <servlet-class>     org.quartz.ee.servlet.QuartzInitializerServlet   </servlet-class>     <load-on-startup>1</load-on-startup>     <init-param>     <param-name>config-file</param-name>     <param-value>/some/path/my_quartz.properties</param-value>   </init-param>     <init-param>     <param-name>shutdown-on-unload</param-name>     <param-value>true</param-value>   </init-param>     <init-param>     <param-name>start-scheduler-on-load</param-name>     <param-value>true</param-value>   </init-param>   </servlet>   <!-- other web.xml items here -->   </web-app>
說明:config-file參數(shù)值是StdSchedulerFactory用來實(shí)例化調(diào)度器的,可以把自己寫的Quartz屬性文件放在classPath即WEB-INF/classes路徑下。
訪問調(diào)度器
從Quartz1.5開始,QuartzInitializerServlet將自動(dòng)儲(chǔ)存StdSchedulerFactory實(shí)例在ServletContext里:
// 從Session中獲得ServletContext
ServletContext ctx =
request.getSession().getServletContext();
// 從ServletContext中獲得StdSchedulerFactory
StdSchedulerFactory factory = (StdSchedulerFactory)ctx.getAttribute(
QuartzFactoryServlet.QUARTZ_FACTORY_KEY);
// 從StdSchedulerFactory中獲得Scheduler
Scheduler scheduler = factory.getScheduler();
// 啟動(dòng)Scheduler
scheduler.start();
FAQ
1.       怎樣控制Job實(shí)例?
看看org.quartz.spi.JobFactory 和 the org.quartz.Scheduler.setJobFactory(..) 方法。
2.       在一個(gè)job完成之后,我怎樣阻止它被刪掉?
設(shè)置JobDetail.setDurability(true)-當(dāng)job是一個(gè)“孤兒”(沒有trigger引用這個(gè)job)時(shí),這將指示Quartz不要?jiǎng)h掉它。
3.       怎樣阻止job并行觸發(fā)?
使job類實(shí)現(xiàn)StatefulJob接口而不是job接口。察看StatefulJob 的JavaDoc。
4.       怎樣使一個(gè)正在執(zhí)行的job停下來?
看看org.quartz.InterruptableJob接口和Scheduler.interrupt(String, String)方法。
5.       怎樣使Jobs的執(zhí)行串聯(lián)起來?
有兩個(gè)方法:
一、用監(jiān)聽器
二、用JobDataMap
6.       怎樣提高JDBC-JobStore的性能?
除了硬件的提高外,我們可以給我們建的Quartz表建索引:
create index idx_qrtz_t_next_fire_time on qrtz_triggers(NEXT_FIRE_TIME);
create index idx_qrtz_t_state on qrtz_triggers(TRIGGER_STATE);
create index idx_qrtz_t_nf_st on qrtz_triggers(TRIGGER_STATE,NEXT_FIRE_TIME);
create index idx_qrtz_ft_trig_name on qrtz_fired_triggers(TRIGGER_NAME);
create index idx_qrtz_ft_trig_group on qrtz_fired_triggers(TRIGGER_GROUP);
create index idx_qrtz_ft_trig_name on qrtz_fired_triggers(TRIGGER_NAME);
create index idx_qrtz_ft_trig_n_g on
qrtz_fired_triggers(TRIGGER_NAME,TRIGGER_GROUP);
create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(INSTANCE_NAME);
create index idx_qrtz_ft_job_name on qrtz_fired_triggers(JOB_NAME);
create index idx_qrtz_ft_job_group on qrtz_fired_triggers(JOB_GROUP);
發(fā)表于 @ 2008年02月20日 11:07:00 |評(píng)論( 0 ) |編輯| 舉報(bào)|收藏
舊一篇:JSTL詳解 | 新一篇:java提出word和pdf等文件的信息
查看最新精華文章 請(qǐng)?jiān)L問博客首頁相關(guān)文章
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
阿里P8架構(gòu)師談:Quartz調(diào)度框架詳解、運(yùn)用場景、與集群部署實(shí)踐 優(yōu)知學(xué)院
Spring整合Quartz輕松完成定時(shí)任務(wù)了解一下?
用 Quartz 進(jìn)行作業(yè)調(diào)度
企業(yè)級(jí)任務(wù)調(diào)度框架Quartz 三 一個(gè)簡單的Quartz 例子
使用Quartz調(diào)度器
Spring 自動(dòng)定時(shí)任務(wù)配置
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服