作业调度框架_Quartz
什么是Quartz
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"
配置環境: 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屬性文件。 整個任務創建及調度的簡單示意圖如下。 Job接口包含唯一方法execute(),將任務邏輯添加到該方法中。StdSchedulerFactory.getScheduler()返回一個可運行的實例,然后創建調度任務的JobDetail實例,并傳遞3個參數給構造方法。第一個參數是任務名,用于引用該任務。第二個參數是任務組名,這里使用默認名,任務組名用于引用集合起來的一組任務,如可以使用Scheduler.pauseJobGroup()來暫停一組任務,每個組中的任務名是唯一的。第三個參數是實現特定任務的類。創建JobDetail實例后,需要創建一個Trigger,這里使用的是SimpleTrigger類,它提供了JDK Timer風格的觸發器行為。傳遞給SimpleTrigger構造方法的兩個參數分別是觸發器名和任務組名,觸發器名在它所在的任務組中必須是唯一的。接下來是設置觸發器的一些屬性,setStartTime()是設置啟動時間,setRepeatInterval()是設置重復間隔,setRepeatCount()是設置重復次數。最后,scheduler.start()啟動調度,終止調度可以用stop()方法。
?CronTrigger類
Quartz有兩大觸發器,除了上面使用的SimpleTrigger外,就是CronTrigger。CronTrigger能夠提供復雜的觸發器表達式的支持。CronTrigger是基于Unix Cron守護進程,它是一個調度程序,支持簡單而強大的觸發器語法。 使用CronTrigger主要的是要掌握Cron表達式。Cron表達式包含6個必要組件和一個可選組件,如下表所示。
| 位置 | 含義 | 允許的特殊字符 |
| 1 | 秒(0~59) | ,?-??*??/ |
| 2 | 分(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表示日歷中星期五(日歷包括星期五)或者第一天(日歷不包括星期五) |
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.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,cron,date-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.
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的作业调度框架_Quartz的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 还在到处集五福?支付宝其实埋了一个鲜为人
- 下一篇: Struts.xml配置解释