java quartz

 什麼是Quartzjava


Quartz是一個徹底由Java編寫的開源做業調度框架,爲在Java應用程序中進行做業調度提供了簡單卻強大的機制。Quartz容許開發人員根據時間間隔來調度做業。它實現了做業和觸發器的多對多的關係,還能把多個做業與不一樣的觸發器關聯。簡單地建立一個org.quarz.Job接口的Java類,Job接口包含惟一的方法:
 
    public  void execute(JobExecutionContext context)  throws JobExecutionException;
 
在Job接口實現類裏面,添加須要的邏輯到execute()方法中。配置好Job實現類並設定好調度時間表,Quartz就會自動在設定的時間調度做業執行execute()。
 
整合了Quartz的應用程序能夠重用不一樣事件的做業,還能夠爲一個事件組合多個做業。Quartz經過屬性文件來配置JDBC事務的數據源、全局做業、觸發器偵聽器、插件、線程池等等。
 
Quartz是由James House建立並最初於2001年春天被加入sourceforge工程。接下來的幾年裏,有不少的新特性和版本出現,可是直到項目遷移到新的站點併成爲OpenSymphony項目家族的一員,纔開始真正啓動並受到也有的關注。
 
目前的版本已是2.0以上,v2.x相對於v1.x有不少新特性出現,並有不少的改動,具體參見Quartz官網上說明。這裏介紹的仍然是v1.x(v1.8.6)。
 
 

 "Hello, Quartz"sql


 
配置環境:
1. 下載Quartz
2. 閱讀Readme.txt,瞭解每一個jar包的做用,將quartz.jar包和lib/下的幾個jar包、以及相關依賴的jar包放在工程的classpath中
 
先來看一個簡單的Quartz應用,讓它每隔5s打印"Hello, Quartz",打印10次。
 
代碼清單1:建立任務
 
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public  class HelloQuartzJob  implements Job {

     public  void execute(JobExecutionContext context) 
             throws JobExecutionException {
        System.out.println("Hello, Quartz! - executing its JOB at "+ 
             new Date() + " by " + context.getTrigger().getName());
    }
}
 
 
爲了調度此任務執行,須要先獲得一個Schedule實例,而後建立一個包含任務信息的JobDetail,最後建立一個Trigger管理任務的執行。
 
代碼清單2:調度任務
import java.sql.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 HelloQuartzScheduling {

     public  static  void main(String[] args) throws SchedulerException {

        SchedulerFactory schedulerFactory =  new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        JobDetail jobDetail =  new JobDetail("helloQuartzJob", 
                Scheduler.DEFAULT_GROUP, HelloQuartzJob. class);

        SimpleTrigger simpleTrigger =  new SimpleTrigger("simpleTrigger", 
                Scheduler.DEFAULT_GROUP);

        simpleTrigger.setStartTime( new Date(System.currentTimeMillis()));
        simpleTrigger.setRepeatInterval(5000);
        simpleTrigger.setRepeatCount(10);

        scheduler.scheduleJob(jobDetail, simpleTrigger);

        scheduler.start();
    }

}
 
運行結果:
 
能夠看到,其實它執行了11次。此處沒有配置log4j.properties屬性文件。
 
整個任務建立及調度的簡單示意圖以下。
初窺Quartz - 紫龍劍 - 倚天萬里須長劍
 
 
Job接口包含惟一方法execute(),將任務邏輯添加到該方法中。StdSchedulerFactory.getScheduler()返回一個可運行的實例,而後建立調度任務的JobDetail實例,並傳遞3個參數給構造方法。第一個參數是任務名,用於引用該任務。第二個參數是任務組名,這裏使用默認名,任務組名用於引用集合起來的一組任務,如可使用Scheduler.pauseJobGroup()來暫停一組任務,每一個組中的任務名是惟一的。第三個參數是實現特定任務的類。建立JobDetail實例後,須要建立一個Trigger,這裏使用的是SimpleTrigger類,它提供了JDK Timer風格的觸發器行爲。傳遞給SimpleTrigger構造方法的兩個參數分別是觸發器名和任務組名,觸發器名在它所在的任務組中必須是惟一的。接下來是設置觸發器的一些屬性,setStartTime()是設置啓動時間,setRepeatInterval()是設置重複間隔,setRepeatCount()是設置重複次數。最後,scheduler.start()啓動調度,終止調度能夠用stop()方法。
 
 

 CronTrigger類express


 
Quartz有兩大觸發器,除了上面使用的SimpleTrigger外,就是CronTrigger。CronTrigger可以提供複雜的觸發器表達式的支持。CronTrigger是基於Unix Cron守護進程,它是一個調度程序,支持簡單而強大的觸發器語法。
 
使用CronTrigger主要的是要掌握Cron表達式。Cron表達式包含6個必要組件和一個可選組件,以下表所示。
 

位置框架

含義google

容許的特殊字符spa

1.net

秒(0~59)插件

, -  *  /線程

2code

分(0~59)

, -  *  /

3

小時(0~24)

, -  *  /

4

日期(1~31)

, -  *  /  ?  L  W  C

5

月(JAN~DEC或1~12)

, -  *  /

6

星期(SUN~SAT或1~7)

, -  *  /  ?  L  C  #

7

年(可選,1970~2099),若爲空,表示所有時間範圍

, -  *  /

 
特殊字符的含義,見下表。
 

特殊字符

說明

*

通配符,任意值

?

無特定值。一般和其餘指定的值一塊兒使用,表示必須顯示該值但不能檢查

-

範圍。e.g.小時部分10-12表示10:00,11:00, 12:00

,

列分隔符。可讓你指定一系列的值。e.g.在星期域中指定MON、TUE和WED

/

增量。表示一個值的增量,e.g.分鐘域中0/1表示從0開始,每次增長1min

L

表示Last。它在日期和星期域中表示有所不一樣。在日期域中,表示這個月的最後一天,而在星期域中,它永遠是7(星期六)。當你但願使用星期中某一天時,L字符很是有用。e.g.星期域中6L表示每個月的最後一個星期五

W

在本月內離當天最近的工做日觸發,所謂的最近工做日,即當天到工做日的先後最短距離,若是當天即爲工做日,則距離是0;所謂本月內指的是不能跨月取到最近工做日,即便前/後月份的最後一天/第一天確實知足最近工做日。e.g. LW表示本月的最後一個工做日觸發,W強烈依賴月份。

#

表示該月的第幾個星期,e.g. 1#2表示每個月的第一個星期一

C

日曆值。日期值是根據一個給定的日曆計算出來的。在日期域中給定一個20C將在20日(日曆包括20日)或20往後日曆中包含的第一天(不包括20日)激活觸發器。例如在一個星期域中使用6C表示日曆中星期五(日曆包括星期五)或者第一天(日曆不包括星期五)

 
Cron表達式舉例:
 
"30 * * * * ?" 每半分鐘觸發任務
"30 10 * * * ?" 每小時的10分30秒觸發任務
"30 10 1 * * ?" 天天1點10分30秒觸發任務
"30 10 1 20 * ?" 每個月20號1點10分30秒觸發任務
"30 10 1 20 10 ? *" 每一年10月20號1點10分30秒觸發任務
"30 10 1 20 10 ? 2011" 2011年10月20號1點10分30秒觸發任務
"30 10 1 ? 10 * 2011" 2011年10月天天1點10分30秒觸發任務
"30 10 1 ? 10 SUN 2011" 2011年10月每週日1點10分30秒觸發任務
"15,30,45 * * * * ?" 每15秒,30秒,45秒時觸發任務
"15-45 * * * * ?" 15到45秒內,每秒都觸發任務
"15/5 * * * * ?" 每分鐘的每15秒開始觸發,每隔5秒觸發一次
"15-30/5 * * * * ?" 每分鐘的15秒到30秒之間開始觸發,每隔5秒觸發一次
"0 0/3 * * * ?" 每小時的第0分0秒開始,每三分鐘觸發一次
"0 15 10 ? * MON-FRI" 星期一到星期五的10點15分0秒觸發任務
"0 15 10 L * ?" 每月最後一天的10點15分0秒觸發任務
"0 15 10 LW * ?" 每月最後一個工做日的10點15分0秒觸發任務
"0 15 10 ? * 5L" 每月最後一個星期四的10點15分0秒觸發任務
"0 15 10 ? * 5#3" 每月第三週的星期四的10點15分0秒觸發任務
 
將上面HelloQuartz例子中SimpleTrigger換成CronTrigger,代碼以下。
 
代碼清單3:CronTrigger調度器
import java.text.ParseException;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;

public  class HelloQuartzScheduling {

     public  static  void main(String[] args) 
         throws SchedulerException, ParseException {

        SchedulerFactory schedulerFactory =  new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        JobDetail jobDetail =  new JobDetail("helloQuartzJob", 
                Scheduler.DEFAULT_GROUP, HelloQuartzJob. class);

         String cronExpression = "30/5 * * * * ?"; // 每分鐘的30s起,每5s觸發任務        
        CronTrigger cronTrigger =  new CronTrigger("cronTrigger", 
                Scheduler.DEFAULT_GROUP, cronExpression);

        scheduler.scheduleJob(jobDetail, cronTrigger);

        scheduler.start();
    }

}
 
運行結果:
 
CronTrigger使用HolidayCalendar類能夠排除某一段時間,好比說國慶節不執行調度任務,代碼示例以下:
 
代碼清單4:HolidayCalendar的使用
import java.text.ParseException;
import java.util.Calendar;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.calendar.HolidayCalendar;


public  class HelloQuartzScheduling {

     public  static  void main(String[] args) 
         throws SchedulerException, ParseException {

        SchedulerFactory schedulerFactory =  new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        JobDetail jobDetail =  new JobDetail("helloQuartzJob", 
                Scheduler.DEFAULT_GROUP, HelloQuartzJob. class);

        Calendar cal = Calendar.getInstance();
        cal.set(2012, Calendar.OCTOBER, 1); // 國慶節

        HolidayCalendar holidayCal =  new HolidayCalendar();
        holidayCal.addExcludedDate(cal.getTime()); // 排除該日期

        // addCalendar(String calName, Calendar calendar, 
        //             boolean replace, boolean updateTriggers)
        scheduler.addCalendar("calendar", holidayCal, true, false);

        String cronExpression = "30/5 * * * * ?"; // 每5s觸發任務        
        CronTrigger cronTrigger =  new CronTrigger("cronTrigger", 
                Scheduler.DEFAULT_GROUP, cronExpression);

        cronTrigger.setCalendarName("calendar");

        scheduler.scheduleJob(jobDetail, cronTrigger);

        scheduler.start();
    }

}
 
 

 JobStore: 任務持久化


Quartz支持任務持久化,這可讓你在運行時增長任務或者對現存的任務進行修改,併爲後續任務的執行持久化這些變動和增長的部分。中心概念是JobStore接口。默認的是RAMJobStore。
 
初窺Quartz - 紫龍劍 - 倚天萬里須長劍
 
 

 配置文件


上述沒有用到任何的配置文件。Quartz支持配置文件,它的好處是比編寫代碼簡單,且修改後不須要從新編譯源碼。
 
>> 配置quartz.properties特性文件
 
quartz.properties文件定義了Quartz應用運行時行爲,還包含了許多能控制Quartz運轉的屬性。它應放在工程的classpath中。
 
代碼清單5:quartz.properties
#============================================================================  
# Configure Main Scheduler Properties  
#============================================================================

# 實例名
org.quartz.scheduler.instanceName = QuartzScheduler 
# 實例ID
org.quartz.scheduler.instanceId = AUTO

#============================================================================
# Configure ThreadPool  
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 線程個數
org.quartz.threadPool.threadCount = 3
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore  
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

#============================================================================
# Configure Plugins 
#============================================================================
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin
# org.quartz.plugins.xml.JobInitializationPlugin是Quartz自帶的插件,
# 默認時,這個插件會在 classpath 中搜索名爲 quartz_jobs.xml 
# 的文件並從中加載 Job 和 Trigger 信息
# v1.8以前用JobInitializationPlugin
#org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames = quartz_jobs.xml
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
org.quartz.plugin.jobInitializer.scanInterval =10
org.quartz.plugin.jobInitializer.wrapInUserTransaction = false

# 關閉quartz新版本檢測功能
org.quartz.scheduler.skipUpdateCheck = true
 
>> 配置quartz_jobs.xml文件
 
在配置quart_jobs.xml時,遇到一個問題:
Exception in thread "main" org.quartz.SchedulerException: SchedulerPlugin class'org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin;' couldnot be instantiated.
 
由於quartz從版本1.8開始,配置文件有所改動,之前quartz自帶的插件是JobInitializationPlugin,而1.8中是XMLSchedulingDataProcessorPlugin. xml schema亦有所改變,難道是改變後配置不對?錯誤提示是插件類找不到,jar包也都加入到工程了啊。最後終於發現,在quartz.properties特性文件中配置插件行最後多打了個分號。原來是一個多餘的分號引起的錯誤!
 
下面是新的xml配置文件格式示例。
 
代碼清單6:quartz_jobs.xml格式  

<?xmlversion="1.0"encoding="UTF-8"?> 

<job-scheduling-dataxmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData" 

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

   xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.ogr/xml/job_scheduling_data_1_8.xsd" 

   version="1.8"

   <pre-processing-commands> 

       <!--在執行做業和觸犯器以前執行的命令--> 

       <delete-jobs-in-group>*</delete-jobs-in-group> 

       <!--刪除標示組中的全部做業,若是是「*」,則刪除全部組中的做業,同時也會刪除與做業有關的觸犯器 --> 

       <delete-triggers-in-group>*</delete-triggers-in-group> 

       <!--刪除標示組中的全部觸犯器,若是是「*」,則刪除全部組中的觸發器 --> 

       <delete-job> 

           <!--刪除指定的做業,同時也會刪除與它關聯的觸犯器 --> 

           <name></name> 

           <group></group> 

       </delete-job> 

       <delete-trigger> 

           <!--刪除指定的觸犯器 --> 

           <name></name> 

           <group></group> 

       </delete-trigger> 

   </pre-processing-commands> 

 

   <processing-directives> 

       <!--在計劃做業和觸發器是應遵循的命令和原則 --> 

       <overwrite-existing-data>true or false</overwrite-existing-data> 

       <!--是否複寫已經存在的任務計劃數據,若是爲false而且ingore-duplicates非false,那麼文件中同名的觸發器或做業將會繼續存在,則會產生錯誤--> 

       <ignore-duplicates>true or false</ignore-duplicates> 

       <!--若是爲true,計劃中的任何同名的做業/觸發器將會被忽略,不會產生錯誤--> 

   </processing-directives> 

 

   <schedule> 

       <job> 

           <name>JobName</name> 

           <group>JobGroup</group> 

           <description></description> 

           <job-class></job-class> 

           <job-listener-ref></job-listener-ref> 

           <!-- volatility,durability,recover必須按順序設定 --> 

           <volatility></volatility> 

           <durability></durability> 

           <recover></recover> 

           <job-data-map> 

               <!-- entry能夠設定多個--> 

               <entry> 

                   <key></key> 

                   <value></value> 

               </entry> 

           </job-data-map> 

       </job> 

       <trigger> 

           <!-- Trigger分爲simple,crondate-interval三種類型,一個trigger中只能指定一種類型--> 

           <simple> 

               <name></name> 

               <group></group> 

               <description></description> 

               <job-name></job-name> 

               <job-group></job-group> 

               <calendar-name></calendar-name> 

               <volatility></volatility> 

               <job-data-map> 

                   <entry> 

                       <key></key> 

                       <value></value> 

                   </entry> 

               </job-data-map> 

               <start-time></start-time> 

               <end-time></end-time> 

               <misfire-instruction></misfire-instruction> 

               <repeat-count></repeat-count> 

               <repeat-interval></repeat-interval> 

           </simple> 

           <cron> 

               <name></name> 

               <group></group> 

               <description></description> 

               <job-name></job-name> 

               <job-group></job-group> 

               <calendar-name></calendar-name> 

               <volatility></volatility> 

               <job-data-map> 

                   <entry> 

                       <key></key> 

                       <value></value> 

                   </entry> 

               </job-data-map> 

               <start-time></start-time> 

               <end-time></end-time> 

               <misfire-instruction></misfire-instruction> 

               <cron-expression></cron-expression> 

               <time-zone></time-zone> 

           </cron> 

           <date-interval> 

               <name></name> 

               <group></group> 

               <description></description> 

               <job-name></job-name> 

               <job-group></job-group> 

               <calendar-name></calendar-name> 

               <volatility></volatility> 

               <job-data-map> 

                   <entry> 

                       <key></key> 

                       <value></value> 

                   </entry> 

               </job-data-map> 

               <start-time></start-time> 

               <end-time></end-time> 

               <misfire-instruction></misfire-instruction> 

               <repeat-interval></repeat-interval> 

               <repeat-interval-unit></repeat-interval-unit> 

           </date-interval> 

       </trigger> 

   </schedule> 

</job-scheduling-data>

 

 
代碼清單7:quartz_jobs.xml示例

 

<?xmlversion="1.0"encoding="UTF-8"?>  

<job-scheduling-dataxmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData" 

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

   xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd" 

   version="1.8">  

      

   <pre-processing-commands>  

       <delete-jobs-in-group>*</delete-jobs-in-group> <!-- clear all jobs in scheduler -->  

       <delete-triggers-in-group>*</delete-triggers-in-group><!-- clear all triggers in scheduler -->  

   </pre-processing-commands>  

      

   <processing-directives>  

       <overwrite-existing-data>true</overwrite-existing-data>  

       <ignore-duplicates>false</ignore-duplicates>   

   </processing-directives>  

      

   <schedule>  

       <job>  

           <name>helloQuartzJob</name>  

           <group>DEFAULT</group>  

           <description>簡單的quartz使用</description>  

           <job-class>HelloQuartzJob</job-class>  

           <volatility>false</volatility>  

           <durability>true</durability>  

           <recover>false</recover>  

       </job>  

       <trigger>  

       <cron>

                <name>trigger</name>     

              <group>DEFAULT</group>     

              <job-name>helloQuartzJob</job-name>     

              <job-group>DEFAULT</job-group> 

             <cron-expression>30/5 * * * * ?</cron-expression>

       </cron>   

       </trigger>

   </schedule>      

</job-scheduling-data>

 
代碼清單8:Quartz任務調度
 
public  class HelloQuartzScheduling {
    
     public  static  void main(String[] args) 
        throws SchedulerException, ParseException {
       
       SchedulerFactory schedulerFactory =  new StdSchedulerFactory();
       Scheduler scheduler = schedulerFactory.getScheduler();
       
       scheduler.start();              
    }   
}

 

 

這裏遇到個問題,提示錯誤:

Exception in thread "main" Java.lang.NoClassDefFoundError: javax/transaction/UserTransaction

 

是因爲缺乏jta.jar,google出的結果是在quartz發行包的/lib中有此jar包,可是在1.8中沒有找到。下載quartz 1.7中,也沒有找到,所以,在網上搜一個jta.jar包放置過程classpath中,而後編譯運行,ok.

相關文章
相關標籤/搜索