|
你曾經(jīng)需要應(yīng)用執(zhí)行一個任務(wù)嗎?這個任務(wù)每天或每周星期二晚上11:30,或許僅僅每個月的最后一天執(zhí)行。一個自動執(zhí)行而無須干預(yù)的任務(wù)在執(zhí)行過程中如果發(fā)生一個嚴(yán)重錯誤,應(yīng)用能夠知到其執(zhí)行失敗并嘗試重新執(zhí)行嗎?你和你的團隊是用java編程嗎?如果這些問題中任何一個你回答是,那么你應(yīng)該使用Quartz調(diào)度器。 旁注:Matrix目前就大量使用到了Quartz。比如,排名統(tǒng)計功能的實現(xiàn),在Jmatrix里通過Quartz定義了一個定時調(diào)度作業(yè),在每天凌晨一點,作業(yè)開始工作,重新統(tǒng)計大家的Karma和排名等。 還有,RSS文件的生成,也是通過Quartz定義作業(yè),每隔半個小時生成一次RSS XML文件。 所以Quartz使用的地方很多,本文無疑是一篇很好的入門和進階的文章,在此,感謝David w Johnson的努力! Quartz讓作業(yè)調(diào)度簡單 Quartz是一個完全由java編寫的開源作業(yè)調(diào)度框架。不要讓作業(yè)調(diào)度這個術(shù)語嚇著你。盡管Quartz框架整合了許多額外功能, 但就其簡易形式看,你會發(fā)現(xiàn)它易用得簡直讓人受不了!。簡單地創(chuàng)建一個實現(xiàn)org.quartz.Job接口的java類。Job接口包含唯一的方法: public void execute(JobExecutionContext context) throws JobExecutionException; 在你的Job接口實現(xiàn)類里面,添加一些邏輯到execute()方法。一旦你配置好Job實現(xiàn)類并設(shè)定好調(diào)度時間表,Quartz將密切注意剩余時間。當(dāng)調(diào)度程序確定該是通知你的作業(yè)的時候,Quartz框架將調(diào)用你Job實現(xiàn)類(作業(yè)類)上的execute()方法并允許做它該做的事情。無需報告任何東西給調(diào)度器或調(diào)用任何特定的東西。僅僅執(zhí)行任務(wù)和結(jié)束任務(wù)即可。如果配置你的作業(yè)在隨后再次被調(diào)用,Quartz框架將在恰當(dāng)?shù)臅r間再次調(diào)用它。 如果你使用了其它流行的開源框架象struts,你會對Quartz的設(shè)計和部件感到舒適。雖然兩個開源工程是解決完全不同的問題,還是有很多相似的之處,就是開源軟件用戶每天感覺很舒適。Quartz能用在單機J2SE應(yīng)用中,作為一個RMI服務(wù)器,也可以用在web應(yīng)用中,甚至也可以用在J2EE應(yīng)用服務(wù)器中。 Quartz的發(fā)展史 盡管Quartz今年開始受到人們注意,但還是暫時流行。Quartz由James House創(chuàng)建并最初于2001年春天被加入sourceforge工程。接下來的幾年里,有許多新特征和版本出現(xiàn),但是直到項目遷移到新的站點并成為OpenSymphony項目家族的一員,才開始真正啟動并受到應(yīng)有的關(guān)注。 James House仍然和幾個協(xié)助他的業(yè)余開發(fā)者參與大量開發(fā)工作。Quartz開發(fā)團隊今年能發(fā)布幾個新版本,包括當(dāng)前正處在候選發(fā)布階段的1.5版。 上手Quartz Quartz工程駐留在OpenSymphony站點上。在Quartz站點上可以找到許多有用的資源:JavaDocs,包含指南的文檔,CVS訪問,用戶和開發(fā)者論壇的連接,當(dāng)然也有下載。 從下載連接取得Quartz的發(fā)布版本,并且解壓到到本地目錄。這個下載文件包含了一個預(yù)先構(gòu)建好的Quartz二進制文件(quartz.jar),你可以將它放進自己的應(yīng)用中。Quartz框架只需要少數(shù)的第三方庫,并且這些三方庫是必需的,你很可能已經(jīng)在使用這些庫了。 你要把Quartz的安裝目錄的<quartz- install>/lib/core 和 <quartz-install>/lib/optional目錄中的第三方庫加進你自己的工程中。大多數(shù)第三方庫是我們所熟知和喜歡的標(biāo)準(zhǔn)Jakarta Commons庫,像Commons Logging, Commons BeantUtils等等。 quartz.properties文件 Quartz有一個叫做quartz.properties的配置文件,它允許你修改框架運行時環(huán)境。缺省是使用Quartz.jar里面的quartz.properties文件。當(dāng)然,你應(yīng)該創(chuàng)建一個quartz.properties文件的副本并且把它放入你工程的classes目錄中以便類裝載器找到它。quartz.properties樣本文件如例1所示。 例1.quartz.properties文件允許修改Quartz運行環(huán)境: #=============================================================== # Configure Main Scheduler Properties #=============================================================== org.quartz.scheduler.instanceName = QuartzSchedulerorg.quartz.scheduler.instanceId = AUTO #=============================================================== # Configure ThreadPool #=============================================================== org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPoolorg.quartz.threadPool.threadCount = 5org.quartz.threadPool.threadPriority = 5 #=============================================================== # Configure JobStore #=============================================================== org.quartz.jobStore.misfireThreshold = 60000org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore 一旦將Quartz.jar文件和第三方庫加到自己的工程里面并且quartz.properties文件在工程的classes目錄中,就可以創(chuàng)建作業(yè)了。然而,在做這之前,我們暫且回避一下先簡短討論一下Quartz架構(gòu)。 Quartz內(nèi)部架構(gòu) 在規(guī)模方面,Quartz跟大多數(shù)開源框架類似。大約有300個java類和接口,并被組織到12個包中。這可以和Apache Struts把大約325個類和接口以及組織到11個包中相比。盡管規(guī)模幾乎不會用來作為衡量框架質(zhì)量的一個特性,但這里的關(guān)鍵是quarts內(nèi)含很多功能,這些功能和特性集是否成為、或者應(yīng)該成為評判一個開源或非開源框架質(zhì)量的因素。 Quartz調(diào)度器 Quartz框架的核心是調(diào)度器。調(diào)度器負(fù)責(zé)管理Quartz應(yīng)用運行時環(huán)境。調(diào)度器不是靠自己做所有的工作,而是依賴框架內(nèi)一些非常重要的部件。Quartz不僅僅是線程和線程管理。為確??缮炜s性,Quartz采用了基于多線程的架構(gòu)。啟動時,框架初始化一套worker線程,這套線程被調(diào)度器用來執(zhí)行預(yù)定的作業(yè)。這就是Quartz怎樣能并發(fā)運行多個作業(yè)的原理。Quartz依賴一套松耦合的線程池管理部件來管理線程環(huán)境。本片文障中,我們會多次提到線程池管理,但Quartz里面的每個對象是可配置的或者是可定制的。所以,例如,如果你想要插進自己線程池管理設(shè)施,我猜你一定能! 作業(yè) 用Quartz的行話講,作業(yè)是一個執(zhí)行任務(wù)的簡單java類。任務(wù)可以是任何java代碼。只需你實現(xiàn)org.quartz.Job接口并且在出現(xiàn)嚴(yán)重錯誤情況下拋出JobExecutionException異常即可。Job接口包含唯一的一個方法execute(),作業(yè)從這里開始執(zhí)行。一旦實現(xiàn)了Job接口和execute()方法,當(dāng)Quartz確定該是作業(yè)運行的時候,它將調(diào)用你的作業(yè)。Execute()方法內(nèi)就完全是你要做的事情。下面有一些你要在作業(yè)里面做事情的例子: · 用JavaMail(或者用其他的像Commons Net一樣的郵件框架)發(fā)送郵件 · 創(chuàng)建遠(yuǎn)程接口并且調(diào)用在EJB上的方法 · 獲取Hibernate Session,查詢和更新關(guān)系數(shù)據(jù)庫里的數(shù)據(jù) · 使用OSWorkflow并且從作業(yè)調(diào)用一個工作流 · 使用FTP和到處移動文件 · 調(diào)用Ant構(gòu)建腳本開始預(yù)定構(gòu)建 這種可能性是無窮的,正事這種無限可能性使得框架功能如此強大。Quartz給你提供了一個機制來建立具有不同粒度的、可重復(fù)的調(diào)度表,于是,你只需創(chuàng)建一個java類,這個類被調(diào)用而執(zhí)行任務(wù)。 作業(yè)管理和存儲 作業(yè)一旦被調(diào)度,調(diào)度器需要記住并且跟蹤作業(yè)和它們的執(zhí)行次數(shù)。如果你的作業(yè)是30分鐘后或每30秒調(diào)用,這不是很有用。事實上,作業(yè)執(zhí)行需要非常準(zhǔn)確和即時調(diào)用在被調(diào)度作業(yè)上的execute()方法。Quartz通過一個稱之為作業(yè)存儲(JobStore)的概念來做作業(yè)存儲和管理。 有效作業(yè)存儲 Quartz提供兩種基本作業(yè)存儲類型。第一種類型叫做RAMJobStore,它利用通常的內(nèi)存來持久化調(diào)度程序信息。這種作業(yè)存儲類型最容易配置、構(gòu)造和運行。對許多應(yīng)用來說,這種作業(yè)存儲已經(jīng)足夠了。然而,因為調(diào)度程序信息是存儲在被分配給JVM的內(nèi)存里面,所以,當(dāng)應(yīng)用程序停止運行時,所有調(diào)度信息將被丟失。如果你需要在重新啟動之間持久化調(diào)度信息,則將需要第二種類型的作業(yè)存儲。 第二種類型的作業(yè)存儲實際上提供兩種不同的實現(xiàn),但兩種實現(xiàn)一般都稱為JDBC作業(yè)存儲。兩種JDBC作業(yè)存儲都需要JDBC驅(qū)動程序和后臺數(shù)據(jù)庫來持久化調(diào)度程序信息。這兩種類型的不同在于你是否想要控制數(shù)據(jù)庫事務(wù)或這釋放控制給應(yīng)用服務(wù)器例如BEA‘s WebLogic或Jboss。(這類似于J2EE領(lǐng)域中,Bean管理的事務(wù)和和容器管理事務(wù)之間的區(qū)別) 這兩種JDBC作業(yè)存儲是: ·JobStoreTX:當(dāng)你想要控制事務(wù)或工作在非應(yīng)用服務(wù)器環(huán)境中是使用 ·JobStoreCMT:當(dāng)你工作在應(yīng)用服務(wù)器環(huán)境中和想要容器控制事務(wù)時使用。 JDBC作業(yè)存儲為需要調(diào)度程序維護調(diào)度信息的用戶而設(shè)計。 作業(yè)和觸發(fā)器 Quartz設(shè)計者做了一個設(shè)計選擇來從調(diào)度分離開作業(yè)。Quartz中的觸發(fā)器用來告訴調(diào)度程序作業(yè)什么時候觸發(fā)??蚣芴峁┝艘话延|發(fā)器類型,但兩個最常用的是SimpleTrigger和CronTrigger。SimpleTrigger為需要簡單打火調(diào)度而設(shè)計。典型地,如果你需要在給定的時間和重復(fù)次數(shù)或者兩次打火之間等待的秒數(shù)打火一個作業(yè),那么SimpleTrigger適合你。另一方面,如果你有許多復(fù)雜的作業(yè)調(diào)度,那么或許需要CronTrigger。 CronTrigger是基于Calendar-like調(diào)度的。當(dāng)你需要在除星期六和星期天外的每天上午10點半執(zhí)行作業(yè)時,那么應(yīng)該使用CronTrigger。正如它的名字所暗示的那樣,CronTrigger是基于Unix克隆表達(dá)式的。 作為一個例子,下面的Quartz克隆表達(dá)式將在星期一到星期五的每天上午10點15分執(zhí)行一個作業(yè)。 0 15 10 ? * MON-FRI 下面的表達(dá)式 0 15 10 ? * 6L 2002-2005 將在2002年到2005年的每個月的最后一個星期五上午10點15分執(zhí)行作業(yè)。 你不可能用SimpleTrigger來做這些事情。你可以用兩者之中的任何一個,但哪個跟合適則取決于你的調(diào)度需要。 調(diào)度一個作業(yè) 讓我們通過看一個例子來進入實際討論?,F(xiàn)假定你管理一個部門,無論何時候客戶在它的FTP服務(wù)器上存儲一個文件,都得用電子郵件通知它。我們的作業(yè)將用FTP登陸到遠(yuǎn)程服務(wù)器并下載所有找到的文件。然后,它將發(fā)送一封含有找到和下載的文件數(shù)量的電子郵件。這個作業(yè)很容易就幫助人們整天從手工執(zhí)行這個任務(wù)中解脫出來,甚至連晚上都無須考慮。我們可以設(shè)置作業(yè)循環(huán)不斷地每60秒檢查一次,而且工作在7×24模式下。這就是Quartz框架完全的用途。 首先創(chuàng)建一個Job類,將執(zhí)行FTP和Email邏輯。下例展示了Quartz的Job類,它實現(xiàn)了org.quartz.Job接口。 例2.從FTP站點下載文件和發(fā)送email的Quartz作業(yè) public class ScanFTPSiteJob implements Job { private static Log logger = LogFactory.getLog(ScanFTPSiteJob.class); /* * Called the scheduler framework at the right time */ public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap jobDataMap = context.getJobDataMap(); try { // Check the ftp site for files File[] files = JobUtil.checkForFiles(jobDataMap); JobUtil.sendEmail(jobDataMap, files); } catch (Exception ex) { throw new JobExecutionException(ex.getMessage()); } }} 我們故意讓ScanFTPSiteJob保持很簡單。我們?yōu)檫@個例子創(chuàng)建了一個叫做JobUtil的實用類。它不是Quartz的組成部分,但對構(gòu)建各種作業(yè)能重用的實用程序庫來說是有意義的。我們可以輕易將那種代碼組織進作業(yè)類中,quarts 調(diào)度器一樣好用,因為我們一直在使用quarts,所以那些代碼可繼續(xù)重用。 JobUtil.checkForFiles() and JobUtil.sendEmail()方法使用的參數(shù)是Quartz創(chuàng)建的JobDataMap的實例。實例為每個作業(yè)的執(zhí)行而創(chuàng)建,它是向作業(yè)類傳遞配置參數(shù)的方法。 這里并沒有展示JobUtil的實現(xiàn),但我們能用Jakarta上的Commons Net輕易地實現(xiàn)FTP和Email功能。 用調(diào)度器調(diào)用作業(yè) 首先創(chuàng)建一個作業(yè),但為使作業(yè)能被調(diào)度器調(diào)用,你得向調(diào)度程序說明你的作業(yè)的調(diào)用時間和頻率。這個事情由與作業(yè)相關(guān)的觸發(fā)器來完成。因為我們僅僅對大約每60秒循環(huán)調(diào)用作業(yè)感興趣,所以打算使用SimpleTrigger。 作業(yè)和觸發(fā)器通過Quartz調(diào)度器接口而被調(diào)度。我們需要從調(diào)度器工廠類取得一個調(diào)度器的實例。最容易的辦法是調(diào)用StdSchedulerFactory這個類上的靜態(tài)方法getDefaultScheduler()。 使用Quartz框架,你需要調(diào)用start()方法來啟動調(diào)度器。例3的代碼遵循了大多數(shù)Quartz應(yīng)用的一般模式:創(chuàng)建一個或多個作業(yè),創(chuàng)建和設(shè)置觸發(fā)器,用調(diào)度器調(diào)度作業(yè)和觸發(fā)器,啟動調(diào)度器。 例3.Quartz作業(yè)通過Quartz調(diào)度器而被調(diào)度 public class MyQuartzServer { public static void main(String[] args) { MyQuartzServer server = new MyQuartzServer(); try { server.startScheduler(); } catch (SchedulerException ex) { ex.printStackTrace(); } } protected void startScheduler() throws SchedulerException { // Use the factory to create a Scheduler instance Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // JobDetail holds the definition for Jobs JobDetail jobDetail = new JobDetail("ScanFTPJob", Scheduler.DEFAULT_GROUP, ScanFTPSiteJob.class);// Store job parameters to be used within execute()jobDetail.getJobDataMap().put("FTP_HOST", "\\home\\cavaness\\inbound"); // Other neccessary Job parameters here // Create a Trigger that fires every 60 seconds Trigger trigger = TriggerUtils.makeSecondlyTrigger(60); // Setup the Job and Trigger with the Scheduler scheduler.scheduleJob(jobDetail, trigger ); // Start the Scheduler running scheduler.start(); }} 編程調(diào)度同聲明性調(diào)度 例3中,我們通過編程的方法調(diào)度我們的ScanFTPSiteJob作業(yè)。就是說,我們用java代碼來設(shè)置作業(yè)和觸發(fā)器。Quartz框架也支持在xml文件里面申明性的設(shè)置作業(yè)調(diào)度。申明性方法允許我們更快速地修改哪個作業(yè)什么時候被執(zhí)行。 Quartz框架有一個插件,這個插件負(fù)責(zé)讀取xml配置文件。xml配置文件包含了關(guān)于啟動Quartz應(yīng)用的作業(yè)和觸發(fā)器信息。所有xml文件中的作業(yè)連同相關(guān)的觸發(fā)器都被加進調(diào)度器。你仍然需要編寫作業(yè)類,但配置那些作業(yè)類的調(diào)度器則非常動態(tài)化。例4展示了一個用申明性方式執(zhí)行與例3代碼相同的邏輯的xml配置文件。 例4.能使用xml文件調(diào)度的作業(yè) <?xml version=‘1.0‘ encoding=‘utf-8‘?><quartz> <job> <job-detail> <name>ScanFTPSiteJob</name> <group>DEFAULT</group> <description> A job that scans an ftp site for files </description> <job-class>ScanFTPSiteJob</job-class> <job-data-map allows-transient-data="true"> <entry> <key>FTP_HOST</key> <value>\home\cavaness\inbound</value> </entry> <!-- Other neccessary Job parameters here --> </job-data-map> </job-detail> <trigger> <simple> <name>ScanFTPSiteJobTrigger</name> <group>DEFAULT</group> <job-name>ScanFTPSiteJob</job-name> <job-group>DEFAULT</job-group> <start-time>2005-09-11 6:10:00 PM</start-time> <!-- repeat indefinitely every 60 seconds --> <repeat-count>-1</repeat-count> <repeat-interval>60000</repeat-interval> </simple> </trigger> </job></quartz> 你可以將xml文件中的元素跟例3代碼作個比較,它們從概念上來看是相同的。使用例4式的申明性方法的好處是維護變得極其簡單,只需改變xml配置文件和重新啟動Quartz應(yīng)用即可。無須修改代碼,無須重新編譯,無須重新部署。 有狀態(tài)和無狀態(tài)作業(yè) 在本文中你所看到的作業(yè)到是無狀態(tài)的。這意味著在兩次作業(yè)執(zhí)行之間,不會去維護作業(yè)執(zhí)行時JobDataMap的狀態(tài)改變。如果你需要能增、刪,改JobDataMap的值,而且能讓作業(yè)在下次執(zhí)行時能看到這個狀態(tài)改變,則需要用Quartz有狀態(tài)作業(yè)。 如果你是一個有經(jīng)驗的EJB開發(fā)者的話,深信你會立即退縮,因為有狀態(tài)帶有負(fù)面含義。這主要是由于EJB帶來的伸縮性問題。Quartz有狀態(tài)作業(yè)實現(xiàn)了org.quartz.StatefulJob接口。無狀態(tài)和有狀態(tài)作業(yè)的關(guān)鍵不同是有狀態(tài)作業(yè)在每次執(zhí)行時只有一個實例。大多數(shù)情況下,有狀態(tài)的作業(yè)不回帶來大的問題。然而,如果你有一個需要頻繁執(zhí)行的作業(yè)或者需要很長時間才能完成的作業(yè),那么有狀態(tài)作業(yè)可能給你帶來伸縮性問題。 Quartz框架的其他特征 Quartz框架有一個豐富的特征集。事實上,quarts有太多特性以致不能在一種情況中全部領(lǐng)會,下面列出了一些有意思的特征,但沒時間在此詳細(xì)討論。 監(jiān)聽器和插件 每個人都喜歡監(jiān)聽和插件。今天,幾乎下載任何開源框架,你必定會發(fā)現(xiàn)支持這兩個概念。監(jiān)聽是你創(chuàng)建的java類,當(dāng)關(guān)鍵事件發(fā)生時會收到框架的回調(diào)。例如,當(dāng)一個作業(yè)被調(diào)度、沒有調(diào)度或觸發(fā)器終止和不再打火時,這些都可以通過設(shè)置來來通知你的監(jiān)聽器。Quartz框架包含了調(diào)度器監(jiān)聽、作業(yè)和觸發(fā)器監(jiān)聽。你可以配置作業(yè)和觸發(fā)器監(jiān)聽為全局監(jiān)聽或者是特定于作業(yè)和觸發(fā)器的監(jiān)聽。 一旦你的一個具體監(jiān)聽被調(diào)用,你就能使用這個技術(shù)來做一些你想要在監(jiān)聽類里面做的事情。例如,你如果想要在每次作業(yè)完成時發(fā)送一個電子郵件,你可以將這個邏輯寫進作業(yè)里面,也可以JobListener里面。寫進JobListener的方式強制使用松耦合有利于設(shè)計上做到更好。 Quartz插件是一個新的功能特性,無須修改Quartz源碼便可被創(chuàng)建和添加進Quartz框架。他為想要擴展Quartz框架又沒有時間提交改變給Quartz開發(fā)團隊和等待新版本的開發(fā)人員而設(shè)計。如果你熟悉Struts插件的話,那么完全可以理解Quartz插件的使用。 與其Quartz提供一個不能滿足你需要的有限擴展點,還不如通過使用插件來擁有可修整的擴展點。 集群Quartz應(yīng)用 Quartz應(yīng)用能被集群,是水平集群還是垂直集群取決于你自己的需要。集群提供以下好處: ·伸縮性 ·搞可用性 ·負(fù)載均衡 目前,Quartz只能借助關(guān)系數(shù)據(jù)庫和JDBC作業(yè)存儲支持集群。將來的版本這個制約將消失并且用RAMJobStore集群將是可能的而且將不需要數(shù)據(jù)庫的支持。 Quartz web應(yīng)用 使用框架幾個星期或幾個月后,Quartz用戶所顯示的需求之一是需要集成Quartz到圖形用戶界面中。目前Quartz框架已經(jīng)有一些工具允許你使用Java servlet來初始化和啟動Quartz。一旦你可以訪問調(diào)度器實例,你就可以把它存儲在web容器的servlet上下文中(ServletContext中)并且可以通過調(diào)度器接口管理調(diào)度環(huán)境。 幸運的是一些開發(fā)者已正影響著單機Quartz web應(yīng)用,它用來更好地管理調(diào)度器環(huán)境。構(gòu)建在若干個流行開源框架如Struts和Spring之上的圖形用戶界面支持很多功能,這些功能都被包裝進一個簡單接口。GUI的一個畫面如圖1所示: ![]() 圖1.Quartz Web應(yīng)用允許比較容易地管理Quartz環(huán)境。 Quartz的下一步計劃 Quartz是一個活動中的工程。Quartz開發(fā)團隊明確表示不會停留在已有的榮譽上。Quartz下一個主要版本已經(jīng)在啟動中。你可以在OpenSymphony的 wiki上體驗一下Quartz 2.0的設(shè)計和特征。 總之,Quartz用戶每天都自由地添加特性建議和設(shè)計創(chuàng)意以便能被核心框架考慮(看重)。 了解更多Quartz特征 當(dāng)你開始使用Quartz框架的更多特性時,User and Developer Forum論壇變成一個回答問題和跟其他Quartz用戶溝通的極其有用的資源。經(jīng)常去逛逛這個論壇時很有好處的,你也可以依靠James House來共享與你的需要相關(guān)的知識和意見。 這個論壇時免費的,你不必登陸便可以查找和查看歸檔文件。然而,如果你覺得這個論壇比較好而且需要向某人回復(fù)問題時,你必須得申請一個免費賬號并用該賬號登陸。 |
|
|