posts - 19, comments - 53, trackbacks - 0, articles - 283
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          Spring Quartz 框架結(jié)構(gòu)概述(一)

          Posted on 2010-05-27 12:59 Gavin.lee 閱讀(2837) 評論(0)  編輯  收藏 所屬分類: SSH2 --Spring
          概述

          各種企業(yè)應(yīng)用幾乎都會碰到任務(wù)調(diào)度的需求,就拿論壇來說:每隔半個小時生成精華文章的RSS文件,每天凌晨統(tǒng)計論壇用戶的積分排名,每隔30分鐘執(zhí)行鎖定用戶解鎖任務(wù)。

          對于一個典型的MIS系統(tǒng)來說,在每月1號凌晨統(tǒng)計上個月各部門的業(yè)務(wù)數(shù)據(jù)生成月報表,每半個小時查詢用戶是否已經(jīng)有快到期的待處理業(yè)務(wù)……,這樣的例子俯拾皆是,不勝枚舉。

          任務(wù)調(diào)度本身涉及到多線程并發(fā)、運行時間規(guī)則制定和解析、場景保持與恢復(fù)、線程池維護等諸多方面的工作。如果直接使用自定義線程這種刀耕火種的原始辦法,開發(fā)任務(wù)調(diào)度程序是一項頗具挑戰(zhàn)性的工作。Java開源的好處就是:領(lǐng)域問題都能找到現(xiàn)成的解決方案。

          OpenSymphony所提供的Quartz2001年發(fā)布版本以來已經(jīng)被眾多項目作為任務(wù)調(diào)度的解決方案,Quartz在提供巨大靈活性的同時并未犧牲其簡單性,它所提供的強大功能使你可以應(yīng)付絕大多數(shù)的調(diào)度需求。

          Quartz 在開源任務(wù)調(diào)度框架中的翹首,它提供了強大任務(wù)調(diào)度機制,難能可貴的是它同時保持了使用的簡單性。Quartz 允許開發(fā)人員靈活地定義觸發(fā)器的調(diào)度時間表,并可以對觸發(fā)器和任務(wù)進行關(guān)聯(lián)映射。

          此外,Quartz提供了調(diào)度運行環(huán)境的持久化機制,可以保存并恢復(fù)調(diào)度現(xiàn)場,即使系統(tǒng)因故障關(guān)閉,任務(wù)調(diào)度現(xiàn)場數(shù)據(jù)并不會丟失。此外,Quartz還提供了組件式的偵聽器、各種插件、線程池等功能。

          了解Quartz體系結(jié)構(gòu)

          Quartz對任務(wù)調(diào)度的領(lǐng)域問題進行了高度的抽象,提出了調(diào)度器、任務(wù)和觸發(fā)器這3個核心的概念,并在org.quartz通過接口和類對重要的這些核心概念進行描述:

          ●Job:是一個接口,只有一個方法void execute(JobExecutionContext context),開發(fā)者實現(xiàn)該接口定義運行任務(wù),JobExecutionContext類提供了調(diào)度上下文的各種信息。Job運行時的信息保存在JobDataMap實例中;

          ●JobDetailQuartz在每次執(zhí)行Job時,都重新創(chuàng)建一個Job實例,所以它不直接接受一個Job的實例,相反它接收一個Job實現(xiàn)類,以便運行時通過newInstance()的反射機制實例化Job。因此需要通過一個類來描述Job的實現(xiàn)類及其它相關(guān)的靜態(tài)信息,如Job名字、描述、關(guān)聯(lián)監(jiān)聽器等信息,JobDetail承擔(dān)了這一角色。

          通過該類的構(gòu)造函數(shù)可以更具體地了解它的功用:JobDetail(java.lang.String name, java.lang.String group, java.lang.Class jobClass),該構(gòu)造函數(shù)要求指定Job的實現(xiàn)類,以及任務(wù)在Scheduler中的組名和Job名稱;

          ●Trigger:是一個類,描述觸發(fā)Job執(zhí)行的時間觸發(fā)規(guī)則。主要有SimpleTriggerCronTrigger這兩個子類。當(dāng)僅需觸發(fā)一次或者以固定時間間隔周期執(zhí)行,SimpleTrigger是最適合的選擇;而CronTrigger則可以通過Cron表達(dá)式定義出各種復(fù)雜時間規(guī)則的調(diào)度方案:如每早晨9:00執(zhí)行,周一、周三、周五下午5:00執(zhí)行等;

          ●Calendarorg.quartz.Calendarjava.util.Calendar不同,它是一些日歷特定時間點的集合(可以簡單地將org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一個日歷時間點,無特殊說明后面的Calendar即指org.quartz.Calendar)。一個Trigger可以和多個Calendar關(guān)聯(lián),以便排除或包含某些時間點。

          假設(shè),我們安排每周星期一早上10:00執(zhí)行任務(wù),但是如果碰到法定的節(jié)日,任務(wù)則不執(zhí)行,這時就需要在Trigger觸發(fā)機制的基礎(chǔ)上使用Calendar進行定點排除。針對不同時間段類型,Quartzorg.quartz.impl.calendar包下提供了若干個Calendar的實現(xiàn)類,如AnnualCalendarMonthlyCalendarWeeklyCalendar分別針對每年、每月和每周進行定義;

          ●Scheduler:代表一個Quartz的獨立運行容器,TriggerJobDetail可以注冊到Scheduler中,兩者在Scheduler中擁有各自的組及名稱,組及名稱是Scheduler查找定位容器中某一對象的依據(jù),Trigger的組及名稱必須唯一,JobDetail的組和名稱也必須唯一(但可以和Trigger的組和名稱相同,因為它們是不同類型的)。Scheduler定義了多個接口方法,允許外部通過組及名稱訪問和控制容器中TriggerJobDetail

          Scheduler可以將Trigger綁定到某一JobDetail中,這樣當(dāng)Trigger觸發(fā)時,對應(yīng)的Job就被執(zhí)行。一個Job可以對應(yīng)多個Trigger,但一個Trigger只能對應(yīng)一個Job。可以通過SchedulerFactory創(chuàng)建一個Scheduler實例。Scheduler擁有一個SchedulerContext,它類似于ServletContext,保存著Scheduler上下文信息,JobTrigger都可以訪問SchedulerContext內(nèi)的信息。SchedulerContext內(nèi)部通過一個Map,以鍵值對的方式維護這些上下文數(shù)據(jù),SchedulerContext為保存和獲取數(shù)據(jù)提供了多個put()getXxx()的方法。可以通過Scheduler# getContext()獲取對應(yīng)的SchedulerContext實例;

          ●ThreadPoolScheduler使用一個線程池作為任務(wù)運行的基礎(chǔ)設(shè)施,任務(wù)通過共享線程池中的線程提高運行效率。

          Job有一個StatefulJob子接口,代表有狀態(tài)的任務(wù),該接口是一個沒有方法的標(biāo)簽接口,其目的是讓Quartz知道任務(wù)的類型,以便采用不同的執(zhí)行方案。無狀態(tài)任務(wù)在執(zhí)行時擁有自己的JobDataMap拷貝,對JobDataMap的更改不會影響下次的執(zhí)行。而有狀態(tài)任務(wù)共享共享同一個JobDataMap實例,每次任務(wù)執(zhí)行對JobDataMap所做的更改會保存下來,后面的執(zhí)行可以看到這個更改,也即每次執(zhí)行任務(wù)后都會對后面的執(zhí)行發(fā)生影響。

          正因為這個原因,無狀態(tài)的Job可以并發(fā)執(zhí)行,而有狀態(tài)的StatefulJob不能并發(fā)執(zhí)行,這意味著如果前次的StatefulJob還沒有執(zhí)行完畢,下一次的任務(wù)將阻塞等待,直到前次任務(wù)執(zhí)行完畢。有狀態(tài)任務(wù)比無狀態(tài)任務(wù)需要考慮更多的因素,程序往往擁有更高的復(fù)雜度,因此除非必要,應(yīng)該盡量使用無狀態(tài)的Job

          如果Quartz使用了數(shù)據(jù)庫持久化任務(wù)調(diào)度信息,無狀態(tài)的JobDataMap僅會在Scheduler注冊任務(wù)時保持一次,而有狀態(tài)任務(wù)對應(yīng)的JobDataMap在每次執(zhí)行任務(wù)后都會進行保存。

          Trigger自身也可以擁有一個JobDataMap,其關(guān)聯(lián)的Job可以通過JobExecutionContext#getTrigger().getJobDataMap()獲取Trigger中的JobDataMap。不管是有狀態(tài)還是無狀態(tài)的任務(wù),在任務(wù)執(zhí)行期間對TriggerJobDataMap所做的更改都不會進行持久,也即不會對下次的執(zhí)行產(chǎn)生影響。

          Quartz擁有完善的事件和監(jiān)聽體系,大部分組件都擁有事件,如任務(wù)執(zhí)行前事件、任務(wù)執(zhí)行后事件、觸發(fā)器觸發(fā)前事件、觸發(fā)后事件、調(diào)度器開始事件、關(guān)閉事件等等,可以注冊相應(yīng)的監(jiān)聽器處理感興趣的事件。

          1描述了Scheduler的內(nèi)部組件結(jié)構(gòu),SchedulerContext提供Scheduler全局可見的上下文信息,每一個任務(wù)都對應(yīng)一個JobDataMap,虛線表達(dá)的JobDataMap表示對應(yīng)有狀態(tài)的任務(wù):


          1 Scheduler結(jié)構(gòu)圖

          一個Scheduler可以擁有多個Triger組和多個JobDetail組,注冊TriggerJobDetail時,如果不顯式指定所屬的組,Scheduler將放入到默認(rèn)組中,默認(rèn)組的組名為Scheduler.DEFAULT_GROUP。組名和名稱組成了對象的全名,同一類型對象的全名不能相同。

          Scheduler本身就是一個容器,它維護著Quartz的各種組件并實施調(diào)度的規(guī)則。Scheduler還擁有一個線程池,線程池為任務(wù)提供執(zhí)行線程——這比執(zhí)行任務(wù)時簡單地創(chuàng)建一個新線程要擁有更高的效率,同時通過共享節(jié)約資源的占用。通過線程池組件的支持,對于繁忙度高、壓力大的任務(wù)調(diào)度,Quartz將可以提供良好的伸縮性。

          提示: Quartz完整下載包examples目錄下?lián)碛?/span>10多個實例,它們是快速掌握Quartz應(yīng)用很好的實例。

          主站蜘蛛池模板: 黑山县| 辽中县| 读书| 涪陵区| 宁陕县| 合川市| 垦利县| 长乐市| 台中市| 蒙阴县| 周宁县| 蚌埠市| 逊克县| 临朐县| 高安市| 乐安县| 建平县| 甘孜县| 长武县| 金昌市| 策勒县| 博客| 武宣县| 拉孜县| 嘉峪关市| 新乐市| 柳江县| 绥棱县| 乌兰浩特市| 镇雄县| 乐平市| 祁连县| 和林格尔县| 友谊县| 西昌市| 石城县| 庆安县| 竹山县| 宁强县| 灵璧县| 株洲市|