天天看點

詳細講解Quartz如何從入門到精通

Quartz是一個開源的作業排程架構,它完全由Java寫成,并設計用于J2SE和J2EE應用中。它提供了巨大的靈活性而不犧牲簡單性。你能夠用它來為執行一個作業而建立簡單的或複雜的排程。它有很多特征,如:資料庫支援,叢集,插件,EJB作業預建構,JavaMail及其它,支援cron-like表達式等等。

本文内容

1、Quartz讓任務排程簡單

2、Quartz的發展史

3、上手Quartz

4、Quartz内部架構

5、作業

6、作業管理和存儲

7、有效作業存儲

8、作業和觸發器

9、排程一個作業

10、用排程器(Scheduler)調用你的作業

11、程式設計排程同聲明性排程

12、有狀态和無狀态作業

13、Quartz架構的其他特征

14、Quartz下一步計劃

15、了解更多Quartz特征

你曾經需要應用執行一個任務嗎?這個任務每天或每周星期二晚上11:30,或許僅僅每個月的最後一天執行。一個自動執行而無須幹預的任務在執行過程中如果發生一個嚴重錯誤,應用能夠知到其執行失敗并嘗試重新執行嗎?你和你的團隊是用Java程式設計嗎?如果這些問題中任何一個你回答是,那麼你應該使用Quartz排程器。

旁注:Matrix目前就大量使用到了Quartz。比如,排名統計功能的實作,在Jmatrix裡通過Quartz定義了一個定時排程作業,在每天淩晨一點,作業開始工作,重新統計大家的Karma和排名等。

還有,RSS檔案的生成,也是通過Quartz定義作業,每隔半個小時生成一次RSS XML檔案。

是以Quartz使用的地方很多,本文無疑是一篇很好的入門和進階的文章,在此,感謝David w Johnson的努力!

Quartz讓作業排程簡單

Quartz是一個完全由Java編寫的開源作業排程架構。不要讓作業排程這個術語吓着你。盡管Quartz架構整合了許多額外功能,但就其簡易形式看,你會發現它易用得簡直讓人受不了!。簡單地建立一個實作org.quartz.Job接口的Java類。Job接口包含唯一的方法:

詳細講解Quartz如何從入門到精通

在你的Job接口實作類裡面,添加一些邏輯到execute()方法。一旦你配置好Job實作類并設定好排程時間表,Quartz将密切注意剩餘時間。當排程程式确定該是通知你的作業的時候,Quartz架構将調用你Job實作類(作業類)上的execute()方法并允許做它該做的事情。無需報告任何東西給排程器或調用任何特定的東西。僅僅執行任務和結束任務即可。如果配置你的作業在随後再次被調用,Quartz架構将在恰當的時間再次調用它。

如果你使用了其它流行的開源架構象struts,你會對Quartz的設計和部件感到舒适。雖然兩個開源工程是解決完全不同的問題,還是有很多相似的之處,就是開源軟體使用者每天感覺很舒适。Quartz能用在單機J2SE應用中,作為一個RMI伺服器,也可以用在web應用中,甚至也可以用在J2EE應用伺服器中。

Quartz的發展史

盡管Quartz今年開始受到人們注意,但還是暫時流行。Quartz由James House建立并最初于2001年春天被加入sourceforge工程。接下來的幾年裡,有許多新特征和版本出現,但是直到項目遷移到新的站點并成為OpenSymphony項目家族的一員,才開始真正啟動并受到應有的關注。

James House仍然和幾個協助他的業餘開發者參與大量開發工作。Quartz開發團隊今年能釋出幾個新版本,包括目前正處在候選釋出階段的1.5版。

上手Quartz

Quartz工程駐留在OpenSymphony站點上。在Quartz站點上可以找到許多有用的資源:JavaDocs,包含指南的文檔,CVS通路,使用者和開發者論壇的連接配接,當然也有下載下傳。

從下載下傳連接配接取得Quartz的釋出版本,并且解壓到到本地目錄。這個下載下傳檔案包含了一個預先建構好的Quartz二進制檔案(quartz.jar),你可以将它放進自己的應用中。Quartz架構隻需要少數的第三方庫,并且這些三方庫是必需的,你很可能已經在使用這些庫了。

你要把Quartz的安裝目錄的/lib/core 和 /lib/optional目錄中的第三方庫加進你自己的工程中。大多數第三方庫是我們所熟知和喜歡的标準Jakarta Commons庫,像Commons Logging, Commons BeantUtils等等。

quartz.properties檔案

Quartz有一個叫做quartz.properties的配置檔案,它允許你修改架構運作時環境。預設是使用Quartz.jar裡面的quartz.properties檔案。當然,你應該建立一個quartz.properties檔案的副本并且把它放入你工程的classes目錄中以便類裝載器找到它。quartz.properties樣本檔案如例1所示。

例1.quartz.properties檔案允許修改Quartz運作環境:

詳細講解Quartz如何從入門到精通

一旦将Quartz.jar檔案和第三方庫加到自己的工程裡面并且quartz.properties檔案在工程的classes目錄中,就可以建立作業了。然而,在做這之前,我們暫且回避一下先簡短讨論一下Quartz架構。

Quartz内部架構

在規模方面,Quartz跟大多數開源架構類似。大約有300個Java類和接口,并被組織到12個包中。這可以和Apache Struts把大約325個類和接口以及組織到11個包中相比。盡管規模幾乎不會用來作為衡量架構品質的一個特性,但這裡的關鍵是quarts内含很多功能,這些功能和特性集是否成為、或者應該成為評判一個開源或非開源架構品質的因素。

Quartz排程器

Quartz架構的核心是排程器。排程器負責管理Quartz應用運作時環境。排程器不是靠自己做所有的工作,而是依賴架構内一些非常重要的部件。Quartz不僅僅是線程和線程管理。為確定可伸縮性,Quartz采用了基于多線程的架構。

啟動時,架構初始化一套worker線程,這套線程被排程器用來執行預定的作業。這就是Quartz怎樣能并發運作多個作業的原理。Quartz依賴一套松耦合的線程池管理部件來管理線程環境。本文中,我們會多次提到線程池管理,但Quartz裡面的每個對象是可配置的或者是可定制的。是以,例如,如果你想要插進自己線程池管理設施,我猜你一定能!

作業

用Quartz的行話講,作業是一個執行任務的簡單Java類。任務可以是任何Java代碼。隻需你實作org.quartz.Job接口并且在出現嚴重錯誤情況下抛出JobExecutionException異常即可。

Job接口包含唯一的一個方法execute(),作業從這裡開始執行。一旦實作了Job接口和execute()方法,當Quartz确定該是作業運作的時候,它将調用你的作業。Execute()方法内就完全是你要做的事情。下面有一些你要在作業裡面做事情的例子:

· 用JavaMail(或者用其他的像Commons Net一樣的郵件架構)發送郵件

· 建立遠端接口并且調用在EJB上的方法

· 擷取Hibernate Session,查詢和更新關系資料庫裡的資料

· 使用OSWorkflow并且從作業調用一個工作流

· 使用FTP和到處移動檔案

· 調用Ant建構腳本開始預定建構

這種可能性是無窮的,正事這種無限可能性使得架構功能如此強大。Quartz給你提供了一個機制來建立具有不同粒度的、可重複的排程表,于是,你隻需建立一個Java類,這個類被調用而執行任務。

作業管理和存儲

作業一旦被排程,排程器需要記住并且跟蹤作業和它們的執行次數。如果你的作業是30分鐘後或每30秒調用,這不是很有用。事實上,作業執行需要非常準确和即時調用在被排程作業上的execute()方法。Quartz通過一個稱之為作業存儲(JobStore)的概念來做作業存儲和管理。

有效作業存儲

Quartz提供兩種基本作業存儲類型。第一種類型叫做RAMJobStore,它利用通常的記憶體來持久化排程程式資訊。這種作業存儲類型最容易配置、構造和運作。對許多應用來說,這種作業存儲已經足夠了。

然而,因為排程程式資訊是存儲在被配置設定給JVM的記憶體裡面,是以,當應用程式停止運作時,所有排程資訊将被丢失。如果你需要在重新啟動之間持久化排程資訊,則将需要第二種類型的作業存儲。

第二種類型的作業存儲實際上提供兩種不同的實作,但兩種實作一般都稱為JDBC作業存儲。兩種JDBC作業存儲都需要JDBC驅動程式和背景資料庫來持久化排程程式資訊。這兩種類型的不同在于你是否想要控制資料庫事務或這釋放控制給應用伺服器例如BEA's WebLogic或Jboss。(這類似于J2EE領域中,Bean管理的事務和和容器管理事務之間的差別)這兩種JDBC作業存儲是:

· JobStoreTX:當你想要控制事務或工作在非應用伺服器環境中是使用

· JobStoreCMT:當你工作在應用伺服器環境中和想要容器控制事務時使用。

JDBC作業存儲為需要排程程式維護排程資訊的使用者而設計。

作業和觸發器

Quartz設計者做了一個設計選擇來從排程分離開作業。Quartz中的觸發器用來告訴排程程式作業什麼時候觸發。架構提供了一把觸發器類型,但兩個最常用的是SimpleTrigger和CronTrigger。SimpleTrigger為需要簡單打火排程而設計。

典型地,如果你需要在給定的時間和重複次數或者兩次打火之間等待的秒數打火一個作業,那麼SimpleTrigger适合你。另一方面,如果你有許多複雜的作業排程,那麼或許需要CronTrigger。

CronTrigger是基于Calendar-like排程的。當你需要在除星期六和星期天外的每天上午10點半執行作業時,那麼應該使用CronTrigger。正如它的名字所暗示的那樣,CronTrigger是基于Unix克隆表達式的。

作為一個例子,下面的Quartz克隆表達式将在星期一到星期五的每天上午10點15分執行一個作業。

0 15 10 ? * MON-FRI

下面的表達式

0 15 10 ? * 6L 2002-2005

将在2002年到2005年的每個月的最後一個星期五上午10點15分執行作業。你不可能用SimpleTrigger來做這些事情。你可以用兩者之中的任何一個,但哪個跟合适則取決于你的排程需要。

排程一個作業

讓我們通過看一個例子來進入實際讨論。現假定你管理一個部門,無論何時候客戶在它的FTP伺服器上存儲一個檔案,都得用電子郵件通知它。我們的作業将用FTP登陸到遠端伺服器并下載下傳所有找到的檔案。

然後,它将發送一封含有找到和下載下傳的檔案數量的電子郵件。這個作業很容易就幫助人們整天從手工執行這個任務中解脫出來,甚至連晚上都無須考慮。我們可以設定作業循環不斷地每60秒檢查一次,而且工作在7×24模式下。這就是Quartz架構完全的用途。

首先建立一個Job類,将執行FTP和Email邏輯。下例展示了Quartz的Job類,它實作了org.quartz.Job接口。

例2.從FTP站點下載下傳檔案和發送email的Quartz作業

詳細講解Quartz如何從入門到精通

我們故意讓ScanFTPSiteJob保持很簡單。我們為這個例子建立了一個叫做JobUtil的實用類。它不是Quartz的組成部分,但對建構各種作業能重用的實用程式庫來說是有意義的。我們可以輕易将那種代碼組織進作業類中,quarts 排程器一樣好用,因為我們一直在使用quarts,是以那些代碼可繼續重用。

JobUtil.checkForFiles() and JobUtil.sendEmail()方法使用的參數是Quartz建立的JobDataMap的執行個體。執行個體為每個作業的執行而建立,它是向作業類傳遞配置參數的方法。

這裡并沒有展示JobUtil的實作,但我們能用Jakarta上的Commons Net輕易地實作FTP和Email功能。

用排程器調用作業

首先建立一個作業,但為使作業能被排程器調用,你得向排程程式說明你的作業的調用時間和頻率。這個事情由與作業相關的觸發器來完成。因為我們僅僅對大約每60秒循環調用作業感興趣,是以打算使用SimpleTrigger。

作業和觸發器通過Quartz排程器接口而被排程。我們需要從排程器工廠類取得一個排程器的執行個體。最容易的辦法是調用StdSchedulerFactory這個類上的靜态方法getDefaultScheduler()。

使用Quartz架構,你需要調用start()方法來啟動排程器。例3的代碼遵循了大多數Quartz應用的一般模式:建立一個或多個作業,建立和設定觸發器,用排程器排程作業和觸發器,啟動排程器。

例3.Quartz作業通過Quartz排程器而被排程

詳細講解Quartz如何從入門到精通

程式設計排程同聲明性排程

例3中,我們通過程式設計的方法排程我們的ScanFTPSiteJob作業。就是說,我們用Java代碼來設定作業和觸發器。Quartz架構也支援在xml檔案裡面申明性的設定作業排程。申明性方法允許我們更快速地修改哪個作業什麼時候被執行。

Quartz架構有一個插件,這個插件負責讀取xml配置檔案。xml配置檔案包含了關于啟動Quartz應用的作業和觸發器資訊。所有xml檔案中的作業連同相關的觸發器都被加進排程器。你仍然需要編寫作業類,但配置那些作業類的排程器則非常動态化。例4展示了一個用申明性方式執行與例3代碼相同的邏輯的xml配置檔案。

例4.能使用xml檔案排程的作業

詳細講解Quartz如何從入門到精通

你可以将xml檔案中的元素跟例3代碼作個比較,它們從概念上來看是相同的。使用例4式的申明性方法的好處是維護變得極其簡單,隻需改變xml配置檔案和重新啟動Quartz應用即可。無須修改代碼,無須重新編譯,無須重新部署。

有狀态和無狀态作業

在本文中你所看到的作業到是無狀态的。這意味着在兩次作業執行之間,不會去維護作業執行時JobDataMap的狀态改變。如果你需要能增、删,改JobDataMap的值,而且能讓作業在下次執行時能看到這個狀态改變,則需要用Quartz有狀态作業。

如果你是一個有經驗的EJB開發者的話,深信你會立即退縮,因為有狀态帶有負面含義。這主要是由于EJB帶來的伸縮性問題。Quartz有狀态作業實作了org.quartz.StatefulJob接口。

無狀态和有狀态作業的關鍵不同是有狀态作業在每次執行時隻有一個執行個體。大多數情況下,有狀态的作業不回帶來大的問題。然而,如果你有一個需要頻繁執行的作業或者需要很長時間才能完成的作業,那麼有狀态作業可能給你帶來伸縮性問題。

Quartz架構的其他特征

Quartz架構有一個豐富的特征集。事實上,quarts有太多特性以緻不能在一種情況中全部領會,下面列出了一些有意思的特征,但沒時間在此詳細讨論。

監聽器和插件

每個人都喜歡監聽和插件。今天,幾乎下載下傳任何開源架構,你必定會發現支援這兩個概念。監聽是你建立的Java類,當關鍵事件發生時會收到架構的回調。例如,當一個作業被排程、沒有排程或觸發器終止和不再打火時,這些都可以通過設定來來通知你的監聽器。Quartz架構包含了排程器監聽、作業和觸發器監聽。你可以配置作業和觸發器監聽為全局監聽或者是特定于作業和觸發器的監聽。

一旦你的一個具體監聽被調用,你就能使用這個技術來做一些你想要在監聽類裡面做的事情。例如,你如果想要在每次作業完成時發送一個電子郵件,你可以将這個邏輯寫進作業裡面,也可以JobListener裡面。寫進JobListener的方式強制使用松耦合有利于設計上做到更好。

Quartz插件是一個新的功能特性,無須修改Quartz源碼便可被建立和添加進Quartz架構。他為想要擴充Quartz架構又沒有時間送出改變給Quartz開發團隊和等待新版本的開發人員而設計。如果你熟悉Struts插件的話,那麼完全可以了解Quartz插件的使用。

與其Quartz提供一個不能滿足你需要的有限擴充點,還不如通過使用插件來擁有可修整的擴充點。

叢集Quartz應用

Quartz應用能被叢集,是水準叢集還是垂直叢集取決于你自己的需要。叢集提供以下好處:

· 伸縮性

· 搞可用性

· 負載均衡

目前,Quartz隻能借助關系資料庫和JDBC作業存儲支援叢集。将來的版本這個制約将消失并且用RAMJobStore叢集将是可能的而且将不需要資料庫的支援。

Quartz web應用

使用架構幾個星期或幾個月後,Quartz使用者所顯示的需求之一是需要內建Quartz到圖形使用者界面中。目前Quartz架構已經有一些工具允許你使用Java servlet來初始化和啟動Quartz。一旦你可以通路排程器執行個體,你就可以把它存儲在web容器的servlet上下文中(ServletContext中)并且可以通過排程器接口管理排程環境。

幸運的是一些開發者已正影響着單機Quartz web應用,它用來更好地管理排程器環境。建構在若幹個流行開源架構如Struts和Spring之上的圖形使用者界面支援很多功能,這些功能都被包裝進一個簡單接口。GUI的一個畫面如圖1所示:

詳細講解Quartz如何從入門到精通

圖1.Quartz Web應用允許比較容易地管理Quartz環境

Quartz的下一步計劃

Quartz是一個活動中的工程。Quartz開發團隊明确表示不會停留在已有的榮譽上。Quartz下一個主要版本已經在啟動中。你可以在OpenSymphony的 wiki上體驗一下Quartz 2.0的設計和特征。總之,Quartz使用者每天都自由地添加特性建議和設計創意以便能被核心架構考慮(看重)。

了解更多Quartz特征

當你開始使用Quartz架構的更多特性時,User and Developer Forum論壇變成一個回答問題和跟其他Quartz使用者溝通的極其有用的資源。經常去逛逛這個論壇時很有好處的,你也可以依靠James House來共享與你的需要相關的知識和意見。