javascript
Spring-Quartz (一)
?摘自:?http://www.blogjava.net/Jay2009/archive/2009/03/25/259176.html
?
Spring為創建Quartz的Scheduler、Trigger和JobDetail提供了便利的FactoryBean類,以便能夠在Spring 容器中享受注入的好處。此外Spring還提供了一些便利工具類直接將Spring中的Bean包裝成合法的任務。Spring進一步降低了使用Quartz的難度,能以更具Spring風格的方式使用Quartz。概括來說它提供了兩方面的支持:?
1)為Quartz的重要組件類提供更具Bean風格的擴展類;?2)提供創建Scheduler的BeanFactory類,方便在Spring環境下創建對應的組件對象,并結合Spring容器生命周期進行啟動和停止的動作。
?
?
創建JobDetail?
??? 可以直接使用Quartz的JobDetail在Spring中配置一個JobDetail Bean,但是JobDetail使用帶參的構造函數,對于習慣通過屬性配置的Spring用戶來說存在使用上的不便。為此Spring通過擴展JobDetail提供了一個更具Bean風格的JobDetailBean。此外,Spring提供了一個MethodInvokingJobDetailFactoryBean,通過這個FactoryBean可以將Spring容器中Bean的方法包裝成Quartz任務,這樣開發者就不必為Job創建對應的類。?
??? JobDetailBean?
??? JobDetailBean擴展于Quartz的JobDetail。使用該Bean聲明JobDetail時,Bean的名字即是任務的名字,如果沒有指定所屬組,即使用默認組。除了JobDetail中的屬性外,還定義了以下屬性:?
??? ● jobClass:類型為Class,實現Job接口的任務類;?
??? ● beanName:默認為Bean的id名,通過該屬性顯式指定Bean名稱,對應任務的名稱;?
??? ● jobDataAsMap:類型為Map,為任務所對應的JobDataMap提供值。之所以需要提供這個屬性,是因為除非你手工注冊一 個編輯器,你不能直接配置JobDataMap類型的值,所以Spring通過jobDataAsMap設置JobDataMap的值;?
??? ●applicationContextJobDataKey:你可以將Spring ApplicationContext的引用保存到JobDataMap中,以便在Job的代碼中訪問ApplicationContext。為了達到這個目的,你需要指定一個鍵,用以在jobDataAsMap中保存ApplicationContext,如果不設置此鍵,JobDetailBean就不將ApplicationContext放入到JobDataMap中;?
??? ●jobListenerNames:類型為String[],指定注冊在Scheduler中的JobListeners名稱,以便讓這些監聽器對本任務的事件進行監聽。
?下面配置片斷使用JobDetailBean在Spring中配置一個JobDetail:
??? <property?name="jobClass"?value="com.baobaotao.quartz.MyJob"?/>
??? <property?name="jobDataAsMap">①
??????? <map>
??????????? <entry?key="size"?value="10"?/>
??????? </map>
??? </property>
??? <property?name="applicationContextJobDataKey"?value="applicationContext"/>②
</bean>
?? JobDetailBean封裝了MyJob任務類,并為Job對應JobDataMap設置了一個size的數據。此外,通過指定applicationContextJobDataKey讓Job的JobDataMap持有Spring ApplicationContext的引用。這樣,MyJob在運行時就可以通過JobDataMap訪問到size和ApplicationContext了。來看一下MyJob的代碼:?
??MyJob
import?org.quartz.JobExecutionContext;
import?org.quartz.JobExecutionException;
import?org.springframework.context.ApplicationContext;
public?class?MyJob?implements?Job?{
public?void?execute(JobExecutionContext?jctx)?throws?JobExecutionException?{
Map?dataMap?=?jctx.getJobDetail().getJobDataMap();? ①獲取JobDetail關聯的JobDataMap
String?size?=(String)dataMap.get("size");? ②
ApplicationContext?ctx?=?(ApplicationContext)dataMap.get("applicationContext");? ③
System.out.println("size:"+size);
dataMap.put("size",size+"0");? ④對JobDataMap所做的更改是否被會持久,取決于任務的類型
//do?sth?
}
}
??? 在②處獲取size值,在③處還可以根據鍵“applicationContext”獲取ApplicationContext,有了ApplicationContext的引用,Job就可以毫無障礙訪問Spring容器中的任何Bean了。MyJob可以在execute()方法中對JobDataMap進行更改,如④所示。如果MyJob實現Job接口,這個更改對于下一次執行是不可見的,如果MyJob實現StatefulJob接口,這種更改對下一次執行是可見的。
MethodInvokingJobDetailFactoryBean?
??? 通常情況下,任務都定義在一個業務類方法中。這時,為了滿足Quartz Job接口的規定,還需要定義一個引用業務類方法的實現類。為了避免創建這個只包含一行調用代碼的Job實現類,Spring為我們提供了MethodInvokingJobDetailFactoryBean,借由該FactoryBean,我們可以將一個Bean的某個方法封裝成滿足Quartz要求的Job。來看一個具體的例子:
??? <property?name="targetObject"?ref="myService"?/>?? ①?引用一個Bean
??? <property?name="targetMethod"?value="doJob"?/>?? ②?指定目標Bean的方法
??? <property?name="concurrent"?value="false"?/>?? ③?指定最終封裝出的任務是否有狀態
<bean?id="myService"?class="com.baobaotao.service.MyService"/>
??? jobDetail_1將MyService#doJob()封裝成一個任務,同時通過concurrent屬性指定任務的類型,默認情況下封裝為無狀態的任務,如果希望目標封裝為有狀態的任務,僅需要將concurrent設置為false就可以了。Spring通過名為concurrent的屬性指定任務的類型,能夠更直接地描述到任務執行的方式(有狀態的任務不能并發執行,無狀態的任務可并發執行)。?
??? MyService服務類擁有一個doJob()方法,它的代碼如下所示:
??? public?void?doJob(){①被封裝成任務的目標方法
??????? System.out.println("in?MyService.dojob().");
??? }
}
??? doJob()方法即可以是static也可以是非static的,但不能擁有方法入參。通過MethodInvokingJobDetailFactoryBean產生的JobDetail不能被序列化,所以不能被持久化到數據庫中的,如果希望使用持久化任務,則你只能創建正規的Quartz的Job實現類了。
??? 創建Trigger?
??? Quartz中另一個重要的組件就是Trigger,Spring按照相似的思路分別為SimpleTrigger和CronTrigger提供了更具Bean風格的SimpleTriggerBean和CronTriggerBean擴展類,通過這兩個擴展類更容易在Spring中以Bean的方式配置Trigger。?
??? SimpleTriggerBean?
??? 默認情況下,通過SimpleTriggerBean配置的Trigger名字即為Bean的名字,并屬于默認組Trigger組。SimpleTriggerBean在SimpleTrigger的基礎上,新增了以下屬性:?
??? ● jobDetail:對應的JobDetail;?
??? ● beanName:默認為Bean的id名,通過該屬性顯式指定Bean名稱,它對應Trigger的名稱;?
??? ● jobDataAsMap:以Map類型為Trigger關聯的JobDataMap提供值;?
??? ● startDelay:延遲多少時間開始觸發,單位為毫秒,默認為0;?
??? ● triggerListenerNames:類型為String[],指定注冊在Scheduler中的TriggerListener名稱,以便讓這些監聽器對本觸發器的事件進行監聽。?
??? 下面的實例使用SimpleTriggerBean定義了一個Trigger,該Trigger和jobDetail相關聯,延遲10秒后啟動,時間間隔為20秒,重復執行100次。此外,我們還為Trigger設置了JobDataMap數據:
??? <property?name="jobDetail"?ref="jobDetail"?/>
??? <property?name="startDelay"?value="1000"?/>
??? <property?name="repeatInterval"?value="2000"?/>
??? <property?name="repeatCount"?value="100"?/>
??? <property?name="jobDataAsMap">?①
??????? <map>
??????????? <entry?key="count"?value="10"?/>
??????? </map>
??? </property>
</bean>
?? 需要特別注意的是,①處配置的JobDataMap是Trigger的JobDataMap,任務執行時必須通過以下方式獲取配置的值:
public?class?MyJob?implements?StatefulJob?{??? public?void?execute(JobExecutionContext?jctx)?throws?JobExecutionException?{
??????? Map?dataMap?=?jctx.getTrigger().getJobDataMap();? ①獲取Trigger的JobDataMap
??????? String?count?=?dataMap.get("count");
??????? dataMap.put("count","30");?? ②?對JobDataMap的更改不會被持久,不影響下次的執行
??????? …
??? }
}
????CronTriggerBean?
??? CronTriggerBean擴展于CronTrigger,觸發器的名字即為Bean的名字,保存在默認組中。在CronTrigger的基礎上,新增的屬性和SimpleTriggerBean大致相同,配置的方法也和SimpleTriggerBean相似,下面給出一個簡單的例子:
??? <property?name="jobDetail"?ref="jobDetail?"/>
??? <property?name="cronExpression"?value="0/5?*?*?*?*??"/>
</bean>
???
???? 創建Scheduler?
??? Quartz的SchedulerFactory是標準的工廠類,不太適合在Spring環境下使用。此外,為了保證Scheduler能夠感知Spring容器的生命周期,完成自動啟動和關閉的操作,必須讓Scheduler和Spring容器的生命周期相關聯。以便在Spring容器啟動后,Scheduler自動開始工作,而在Spring容器關閉前,自動關閉Scheduler。為此,Spring提供SchedulerFactoryBean,這個FactoryBean大致擁有以下的功能:?
2)讓Scheduler和Spring容器的生命周期建立關聯,相生相息;?
3)通過屬性配置部分或全部代替Quartz自身的配置文件。?
??? 來看一個SchedulerFactoryBean配置的例子:?
????SchedulerFactoryBean配置
??? <property?name="triggers">?①注冊多個Trigger
??????? <list>
??????????? <ref?bean="simpleTrigger"?/>
??????? </list>
??? </property>
??? <property?name="schedulerContextAsMap">??②以Map類型設置SchedulerContext數據
??????? <map>
??????????? <entry?key="timeout"?value="30"?/>
??????? </map>
??? </property>
?? ③顯式指定Quartz的配置文件地址?
?? <property name="configLocation" value="classpath:com/baobaotao/quartz/quartz.properties" />?
</bean>
??? SchedulerFactoryBean的triggers屬性為Trigger[]類型,可以通過該屬性注冊多個Trigger,在①處,我們注冊了一個Trigger。Scheduler擁有一個類似于ServletContext的SchedulerContext。SchedulerFactoryBean允許你以Map的形式設置SchedulerContext的參數值,如②所示。默認情況下,Quartz在類路徑下查詢quartz.properties配置文件,你也可以通過configLocation屬性顯式指定配置文件位置,如③所示。
?
??? 除了實例中所用的屬性外,SchedulerFactoryBean還擁有一些常見的屬性:?
??? ●calendars:類型為Map,通過該屬性向Scheduler注冊Calendar;?
??? ●jobDetails:類型為JobDetail[],通過該屬性向Scheduler注冊JobDetail;?
??? ●autoStartup:SchedulerFactoryBean在初始化后是否馬上啟動Scheduler,默認為true。如果設置為false,需要手工啟動Scheduler;?
??? ●startupDelay:在SchedulerFactoryBean初始化完成后,延遲多少秒啟動Scheduler,默認為0,表示馬上啟動。如果并非馬上擁有需要執行的任務,可通過startupDelay屬性讓Scheduler延遲一小段時間后啟動,以便讓Spring能夠更快初始化容器中剩余的Bean;
??? SchedulerFactoryBean的一個重要功能是允許你將Quartz配置文件中的信息轉移到Spring配置文件中,帶來的好處是,配置信息的集中化管理,同時我們不必熟悉多種框架的配置文件結構。回憶一個Spring集成JPA、Hibernate框架,就知道這是Spring在集成第三方框架經常采用的招數之一。SchedulerFactoryBean通過以下屬性代替框架的自身配置文件:?
??? ●dataSource:當需要使用數據庫來持久化任務調度數據時,你可以在Quartz中配置數據源,也可以直接在Spring中通過dataSource指定一個Spring管理的數據源。如果指定了該屬性,即使quartz.properties中已經定義了數據源,也會被此dataSource覆蓋;?
??? ●transactionManager:可以通過該屬性設置一個Spring事務管理器。在設置dataSource時,Spring強烈推薦你使用一個事務管理器,否則數據表鎖定可能不能正常工作;?
??? ●nonTransactionalDataSource:在全局事務的情況下,如果你不希望Scheduler執行化數據操作參與到全局事務中,則可以通過該屬性指定數據源。在Spring本地事務的情況下,使用dataSource屬性就足夠了;?
??? ●quartzProperties:類型為Properties,允許你在Spring中定義Quartz的屬性。其值將覆蓋quartz.properties配置文件中的設置,這些屬性必須是Quartz能夠識別的合法屬性,在配置時,你可以需要查看Quartz的相關文檔。下面是一個配置quartzProperties屬性的例子:
??? …
??? <property?name="quartzProperties">
??????? <props>
??????????? <prop?key="org.quartz.threadPool.class">??①Quartz屬性項1
??????????????? org.quartz.simpl.SimpleThreadPool
??????????? </prop>
??????????? <prop?key="org.quartz.threadPool.threadCount">10</prop>??①Quartz屬性項2
??????? </props>
??? </property>
</bean>
?? 在實際應用中,我們并不總是在程序部署的時候就可能確定需要哪些任務,往往需要在運行期根據業務數據動態產生觸發器和任務。你完全可以在運行期通過代碼調用SchedulerFactoryBean獲取Scheduler實例,進行動態的任務注冊和調度。
轉載于:https://www.cnblogs.com/chenying99/archive/2012/12/02/2798374.html
總結
以上是生活随笔為你收集整理的Spring-Quartz (一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 添加删除约束脚本 ::fn_get_s
- 下一篇: javascript - dom