程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Quartz從入門到進階

Quartz從入門到進階

編輯:關於JAVA
  你曾經需要應用執行一個任務嗎?這個任務每天或每周星期二晚上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接口包含唯一的方法:
  
  public void execute(JobExecutionContext context)
  throws JobExecutionException;
  
  在你的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的安裝目錄的<quartz- install>/lib/core 和 <quartz-install>/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運行環境:
  
  #===============================================================
  # 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目錄中,就可以創建作業了。然而,在做這之前,我們暫且回避一下先簡短討論一下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作業
  
  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保持很簡單。我們為這個例子創建了一個叫做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調度器而被調度
  
  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();
  }}
  
  編程調度同聲明性調度
  
  例3中,我們通過編程的方法調度我們的ScanFTPSiteJob作業。就是說,我們用Java代碼來設置作業和觸發器。Quartz框架也支持在XML文件裡面申明性的設置作業調度。申明性方法允許我們更快速地修改哪個作業什麼時候被執行。
  
  Quartz框架有一個插件,這個插件負責讀取xml配置文件。xml配置文件包含了關於啟動Quartz應用的作業和觸發器信息。所有xml文件中的作業連同相關的觸發器都被加進調度器。你仍然需要編寫作業類,但配置那些作業類的調度器則非常動態化。例4展示了一個用申明性方式執行與例3代碼相同的邏輯的XML配置文件。
  
  例4.能使用XML文件調度的作業
  
  <?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應用即可。無須修改代碼,無須重新編譯,無須重新部署。
  
  有狀態和無狀態作業
  
  在本文中你所看到的作業到是無狀態的。這意味著在兩次作業執行之間,不會去維護作業執行時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所示:
   
  圖1.Quartz Web應用允許比較容易地管理Quartz環境。
  
  Quartz的下一步計劃
  
  Quartz是一個活動中的工程。Quartz開發團隊明確表示不會停留在已有的榮譽上。Quartz下一個主要版本已經在啟動中。你可以在OpenSymphony的 wiki上體驗一下Quartz 2.0的設計和特征。
  
  總之,Quartz用戶每天都自由地添加特性建議和設計創意以便能被核心框架考慮(看重)。
  
  了解更多Quartz特征
  
  當你開始使用Quartz框架的更多特性時,User and Developer Forum論壇變成一個回答問題和跟其他Quartz用戶溝通的極其有用的資源。經常去逛逛這個論壇時很有好處的,你也可以依靠James House來共享與你的需要相關的知識和意見。
  
  這個論壇時免費的,你不必登陸便可以查找和查看歸檔文件。然而,如果你覺得這個論壇比較好而且需要向某人回復問題時,你必須得申請一個免費帳號並用該帳號登陸。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved