Quartz任務中調用Spring容器中bean及動態調度任務

Quartz 是開源任務調度框架中的翹首,它提供了強大任務調度機制,同時保持了使用的簡單性。Quartz 允許開發人員靈活地定義觸發器的調度時間表,並可以對觸發器和任務進行關聯映射。此外,Quartz提供了調度運行環境的持久化機制,可以保存並恢復調度現場,即使系統因故障關閉,任務調度現場數據並不會丟失。此外,Quartz還提供了組件式的偵聽器、各種插件、線程池等功能。 

Spring爲創建Quartz的Scheduler、Trigger和JobDetail提供了便利的FactoryBean類,以便能夠在Spring 容器中享受注入的好處。此外Spring還提供了一些便利工具類直接將Spring中的Bean包裝成合法的任務。Spring進一步降低了使用Quartz的難度,能以更具Spring風格的方式使用Quartz。概括來說它提供了兩方面的支持: 
1)爲Quartz的重要組件類提供更具Bean風格的擴展類; 
2)提供創建Scheduler的BeanFactory類,方便在Spring環境下創建對應的組件對象,並結合Spring容器生命週期進行啓動和停止的動作。
 

第一步: 配置SchedulerFactoryBean 
Quartz的SchedulerFactory是標準的工廠類,不太適合在Spring環境下使用。此外,爲了保證Scheduler能夠感知Spring容器的生命週期,完成自動啓動和關閉的操作,必須讓Scheduler和Spring容器的生命週期相關聯。以便在Spring容器啓動後,Scheduler自動開始工作,而在Spring容器關閉前,自動關閉Scheduler。爲此,Spring提供SchedulerFactoryBean,這個FactoryBean大致擁有以下的功能: 
1)以更具Bean風格的方式爲Scheduler提供配置信息; 
2)讓Scheduler和Spring容器的生命週期建立關聯,相生相息; 
3)通過屬性配置部分或全部代替Quartz自身的配置文件。 
spring容器中的bean只能放到SchedulerContext裏面傳入job中。 



Java代碼  收藏代碼
  1. <bean name="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >  
  2.                 <!-- 注入數據源 -->    
  3.         <property name="dataSource">    
  4.             <ref bean="dataSource" />    
  5.         </property>  
  6.         <property name="transactionManager" ref="txManager">  
  7.         </property>  
  8.                 <!-- 延遲30秒啓動Scheduler -->    
  9.         <property name="startupDelay" value="30"></property>  
  10.         <property name="schedulerContextAsMap">    
  11.             <map>    
  12.         <!-- spring 管理的service需要放到這裏,才能夠注入成功 -->    
  13.                 <description>schedulerContextAsMap</description>    
  14.                 <entry key="jobService" value-ref="jobService"/>  
  15.             </map>    
  16.         </property>  
  17.                 <!-- 通過applicationContextSchedulerContextKey屬性配置spring上下文 -->    
  18.         <property name="applicationContextSchedulerContextKey">    
  19.             <value>applicationContext</value>    
  20.         </property>   
  21.     </bean>  


SchedulerFactoryBean屬性介紹: 
●triggers:triggers屬性爲Trigger[]類型,可以通過該屬性註冊多個Trigger 
●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的相關文檔。
 

配置好數據源dataSource後,需要在Quartz的QRTZ_LOCKS表中插入以下數據: 
INSERT INTO QRTZ_LOCKS values('TRIGGER_ACCESS'); 
INSERT INTO QRTZ_LOCKS values('JOB_ACCESS'); 
否則會報 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scheduler' defined in file [...\webapps\WEB-INF\classes\config\applicationContext-quartz.xml]: Invocation of init method failed; nested exception is org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: No row exists in table QRTZ_LOCKS for lock named: TRIGGER_ACCESS [See nested exception: java.sql.SQLException: No row exists in table QRTZ_LOCKS for lock named: TRIGGER_ACCESS]]異常
 


第二步 動態添加Job 

              
Java代碼  收藏代碼
  1. JobDetail jobDetail = new JobDetail("jobName""jobGroup",  
  2.             TestJob.class);  
  3.     jobDetail.setDescription("Description");  
  4.     CronTrigger trigger = new CronTrigger("TriggerName",  
  5.             "TriggerGroup""CronContent");  
  6.     try {  
  7.             if (!scheduler.isStarted()) {  
  8.             scheduler.start();  
  9.         }  
  10.         scheduler.scheduleJob(jobDetail, trigger);  
  11.                catch (SchedulerException e) {  
  12.                }  


第三步 實現Job實現類 
Java代碼  收藏代碼
  1. public class TestJob extends QuartzJobBean {  
  2.   
  3.     @Override  
  4.     protected void executeInternal(JobExecutionContext context) throws JobExecutionException {  
  5.         Scheduler scheduler = (Scheduler) context.getScheduler();    
  6.         String jobName = context.getJobDetail().getName();  
  7.         String jobGroup = context.getJobDetail().getGroup();  
  8.         //獲取JobExecutionContext中的service對象    
  9.         try {  
  10.                         //獲取JobExecutionContext中的service對象   
  11.             SchedulerContext schCtx = context.getScheduler().getContext();  
  12.                         //獲取Spring中的上下文    
  13.             ApplicationContext appCtx = (ApplicationContext)schCtx.get("applicationContext");  
  14.             jobService= (JobService)appCtx.getBean("jobService");  
  15.             ....  
  16.         } catch (SchedulerException e1) {  
  17.             // TODO 尚未處理異常  
  18.             e1.printStackTrace();  
  19.         }   
  20.         }   
  21.   
  22.   
  23.     };  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章