用關Quartz在Spring中設置動態定時任務

/////轉載: http://mengqingyu.iteye.com/blog/389275

 轉: http://linqincai.iteye.com/?show_full=true

什麼是動態定時任務:
是由客戶制定生成的,服務端只知道該去執行什麼任務,但任務的定時是不確定的(是由客戶制定)。這樣總不能修改配置文件每定製個定時任務就增加一個trigger吧,即便允許客戶修改配置文件,但總需要重新啓動web服務啊,研究了下Quartz在Spring中的動態定時,發現: cronExpression是關鍵,如果可以動態設置cronExpression的值,也就說如果我們可以直接調用CronTriggerBean中設置cronExpression的方法,就可以順利解決問題了。
① targetMethod: 指定需要定時執行scheduleInfoManager中的simpleJobTest()方法
② concurrent:對於相同的JobDetail,當指定多個Trigger時, 很可能第一個job完成之前,第二個job就開始了。指定concurrent設爲false,多個job不會併發運行,第二個job將不會在第一個job完成之前開始。
③ cronExpression:0/10 * * * * ?表示每10秒執行一次,具體可參考附表。
④ triggers:通過再添加其他的ref元素可在list中放置多個觸發器。scheduleInfoManager中的simpleJobTest()方法注意:此方法沒有參數,如果scheduleInfoManager有兩個方法simpleJobTest()和simpleJobTest(String argument),則spring只會去執行無參的simpleJobTest().
public void simpleJobTest()
{         
   log.warn("uh oh, Job is scheduled !'" + "' Success...");    
}
   Quartz在Spring中動態設置cronTrigger方法一Spring配置文件:
將定時器注入到業務邏輯層Manager 

/////

Xml代碼

  1. <bean id="scheduleInfoManager" class="com.lively.happyoa.jobs.webapp.manager.scheduleInfoManager">  
  2.          <property name="scheduler" ref="schedulerFactory"/>  
  3.      </bean>  
  4.      <bean id="schedulerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
  5.          <property name="targetObject" ref="scheduleInfoManager"/>  
  6.          <property name="targetMethod" value="reScheduleJob"/>  
  7.          <property name="concurrent" value="false"/>  
  8.      </bean>  
  9.      <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" >  
  10.           <property name="jobDetail" ref="schedulerJobDetail"/>  
  11.           <property name="cronExpression">  
  12.               <value>0/10 * * * * ?</value>  
  13.           </property>  
  14.       </bean>  
  15.      <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
  16.          <property name="triggers">  
  17.              <list>  
  18.                  <ref local="cronTrigger"/>  
  19.              </list>  
  20.          </property>  
  21. </bean>

/////

Xml代碼

  1. <bean id="scheduleInfoManager" class="com.lively.happyoa.jobs.webapp.manager.scheduleInfoManager">  
  2.          <property name="scheduler" ref="schedulerFactory"/>  
  3.      </bean>  
  4.      <bean id="schedulerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
  5.          <property name="targetObject" ref="scheduleInfoManager"/>  
  6.          <property name="targetMethod" value="reScheduleJob"/>  
  7.          <property name="concurrent" value="false"/>  
  8.      </bean>  
  9.      <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" >  
  10.           <property name="jobDetail" ref="schedulerJobDetail"/>  
  11.           <property name="cronExpression">  
  12.               <value>0/10 * * * * ?</value>  
  13.           </property>  
  14.       </bean>  
  15.      <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
  16.          <property name="triggers">  
  17.              <list>  
  18.                  <ref local="cronTrigger"/>  
  19.              </list>  
  20.          </property>  
  21. </bean> 

//  scheduleInfoManager中的reScheduleJob ()方法及相關方法① reScheduleJob讀取數據庫,獲得自定義定時器調度時間():

Java代碼

  1. private Scheduler scheduler;    
  2.   
  3. // 設值注入,通過setter方法傳入被調用者的實例scheduler  
  4. public void setScheduler(Scheduler scheduler) {      
  5.      this.scheduler = scheduler;      
  6. }      
  7. rivate void reScheduleJob() throws SchedulerException,ParseException {   
  8.         // 運行時可通過動態注入的scheduler得到trigger,注意採用這種注入方式在有的項目中會有問題,如果遇到注入問題,可以採取在運行方法時候,獲得bean來避免錯誤發生。  
  9.         CronTriggerBean trigger = (CronTriggerBean) scheduler.getTrigger(                "cronTrigger", Scheduler.DEFAULT_GROUP);   
  10.         String dbCronExpression = getCronExpressionFromDB();   
  11.         String originConExpression = trigger.getCronExpression();   
  12.     // 判斷從DB中取得的任務時間(dbCronExpression)和現在的quartz線程中的任務時間(originConExpression)是否相等  
  13.     // 如果相等,則表示用戶並沒有重新設定數據庫中的任務時間,這種情況不需要重新rescheduleJob  
  14.         if(!originConExpression.equalsIgnoreCase(dbCronExpression)){   
  15.             trigger.setCronExpression(dbCronExpression);   
  16.             scheduler.rescheduleJob("cronTrigger", Scheduler.DEFAULT_GROUP, trigger);   
  17.         }   
  18.     // 下面是具體的job內容,可自行設置  
  19.     // executeJobDetail();}  
Java代碼:

  1. private Scheduler scheduler;   
  2.   
  3. // 設值注入,通過setter方法傳入被調用者的實例scheduler  
  4. public void setScheduler(Scheduler scheduler) {     
  5.      this.scheduler = scheduler;     
  6. }     
  7. rivate void reScheduleJob() throws SchedulerException,ParseException {  
  8.         // 運行時可通過動態注入的scheduler得到trigger,注意採用這種注入方式在有的項目中會有問題,如果遇到注入問題,可以採取在運行方法時候,獲得bean來避免錯誤發生。  
  9.         CronTriggerBean trigger = (CronTriggerBean) scheduler.getTrigger(                "cronTrigger", Scheduler.DEFAULT_GROUP);  
  10.         String dbCronExpression = getCronExpressionFromDB();  
  11.         String originConExpression = trigger.getCronExpression();  
  12.     // 判斷從DB中取得的任務時間(dbCronExpression)和現在的quartz線程中的任務時間(originConExpression)是否相等  
  13.     // 如果相等,則表示用戶並沒有重新設定數據庫中的任務時間,這種情況不需要重新rescheduleJob  
  14.         if(!originConExpression.equalsIgnoreCase(dbCronExpression)){  
  15.             trigger.setCronExpression(dbCronExpression);  
  16.             scheduler.rescheduleJob("cronTrigger", Scheduler.DEFAULT_GROUP, trigger);  
  17.         }  
  18.     // 下面是具體的job內容,可自行設置  
  19.     // executeJobDetail();}
////

② getCronExpressionFromDB():從數據庫中獲得dbCronExpression的具體代碼,由於使用了scheduleInfoManager,所以要在定義相應的setter方法:
Java代碼 


  1. private String getCronExpressionFromDB(){   
  2.          String sql="from ScheduleInfo scheduleInfo where 1=1 ";   
  3.          sql=sql+" and scheduleInfo.infoId = '"+"1" + "'";   
  4.          List scheduleList = scheduleInfoManager.queryScheduleInListBySql(sql);   
  5.          ScheduleInfo scheduleInfo = (ScheduleInfo)scheduleList.get(0);   
  6.          String dbCronExpression = scheduleInfo.getCronExpression();   
  7.          return dbCronExpression;   
  8. }  
Java代碼
  1. private String getCronExpressionFromDB(){  
  2.          String sql="from ScheduleInfo scheduleInfo where 1=1 ";  
  3.          sql=sql+" and scheduleInfo.infoId = '"+"1" + "'";  
  4.          List scheduleList = scheduleInfoManager.queryScheduleInListBySql(sql);  
  5.          ScheduleInfo scheduleInfo = (ScheduleInfo)scheduleList.get(0);  
  6.          String dbCronExpression = scheduleInfo.getCronExpression();  
  7.          return dbCronExpression;  
  8. }  

③ 在spring配置文件的scheduleInfoManager配置了相應的property(scheduler/
Java代碼 複製代碼
  1. scheduleInfoManager),要爲其設置setter方法:    
  2. private Scheduler scheduler;   
  3.      // 設值注入,通過setter方法傳入被調用者的實例scheduler  
  4.      public void setScheduler(Scheduler scheduler) {   
  5.          this.scheduler = scheduler;   
  6.     }   
  7.      private ScheduleInfoManager scheduleInfoManager;   
  8.      // 設值注入,通過setter方法傳入被調用者的實例scheduleInfoManager  
  9.      public void setScheduleInfoManager(ScheduleInfoManager scheduleInfoManager){   
  10.          this.scheduleInfoManager = scheduleInfoManager;   
  11.      }  
Java代碼
  1. scheduleInfoManager),要爲其設置setter方法:   
  2. private Scheduler scheduler;  
  3.      // 設值注入,通過setter方法傳入被調用者的實例scheduler  
  4.      public void setScheduler(Scheduler scheduler) {  
  5.          this.scheduler = scheduler;  
  6.     }  
  7.      private ScheduleInfoManager scheduleInfoManager;  
  8.      // 設值注入,通過setter方法傳入被調用者的實例scheduleInfoManager  
  9.      public void setScheduleInfoManager(ScheduleInfoManager scheduleInfoManager){  
  10.          this.scheduleInfoManager = scheduleInfoManager;  
  11.      } 
/////

Quartz在Spring中動態設置cronTrigger方法二在上面的2中我們可以看到,儘管已經可以動態進行rescheduleJob了,不過依然需要我們設置一個cronExpression,如果嘗試一下拿掉spring配置中的        
<property name="cronExpression">
              <value>0/10 * * * * ?</value>
</property>
則容器(如tomcat)啓動時會報錯。實際中我們希望tomcat啓動時就可以直接去讀數據庫,拿到相應的dbCronExpression,然後定時執行一個job,而不希望配置初始的cronExpression ,觀察下面的CronTriggerBean,考慮到cronExpression需要初始化,如果設定一個類InitializingCronTrigger繼承CronTriggerBean,然後在這個類中做一些讀取DB的初始化工作(設置cronExpression),問題就可以解決了。Spring配置文件:

Xml代碼 複製代碼
  1. <bean id="scheduleInfoManager" class="com.lively.happyoa.jobs.webapp.manager.ScheduleInfoManager">         <property name="scheduler" ref="schedulerFactory"/>  
  2.      </bean>  
  3.      <bean id="schedulerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
  4.          <property name="targetObject" ref="scheduleInfoManager"/>  
  5.          <property name="targetMethod" value="reScheduleJob"/>  
  6.          <property name="concurrent" value="false"/>  
  7.      </bean>  
  8.     <bean id="cronTrigger" class="com.lively.happyoa.jobs.webapp.manager.ScheduleInfoManager.InitializingCronTrigger">  
  9.           <property name="jobDetail" ref="schedulerJobDetail"/>  
  10.          <!--<property name="cronExpression">  
  11.               <value>0/10 * * * * ?</value>  
  12.           </property>-->  
  13.          <property name="scheduleInfoManager" ref="scheduleInfoManager"/>  
  14.       </bean>  
  15.      <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
  16.          <property name="triggers">  
  17.              <list>  
  18.                  <ref local="cronTrigger"/>  
  19.              </list>  
  20.          </property>  
  21. </bean>  
Xml代碼
  1. <bean id="scheduleInfoManager" class="com.lively.happyoa.jobs.webapp.manager.ScheduleInfoManager">         <property name="scheduler" ref="schedulerFactory"/>  
  2.      </bean>  
  3.      <bean id="schedulerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
  4.          <property name="targetObject" ref="scheduleInfoManager"/>  
  5.          <property name="targetMethod" value="reScheduleJob"/>  
  6.          <property name="concurrent" value="false"/>  
  7.      </bean>  
  8.     <bean id="cronTrigger" class="com.lively.happyoa.jobs.webapp.manager.ScheduleInfoManager.InitializingCronTrigger">  
  9.           <property name="jobDetail" ref="schedulerJobDetail"/>  
  10.          <!--<property name="cronExpression">  
  11.               <value>0/10 * * * * ?</value>  
  12.           </property>-->  
  13.          <property name="scheduleInfoManager" ref="scheduleInfoManager"/>  
  14.       </bean>  
  15.      <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
  16.          <property name="triggers">  
  17.              <list>  
  18.                  <ref local="cronTrigger"/>  
  19.              </list>  
  20.          </property>  
  21. </bean>  

InitializingCronTrigger中的相關方法注意:在注入scheduleInfoManager屬性的時候,我們可以去讀取DB任務時間(之所以放在setter方法中,是因爲需要在設置scheduleInfoManager後進行getCronExpressionFromDB(),否則,也可以①②邏輯把放在類的構造函數中).注意InitializingCronTrigger必須extends CronTriggerBean.
Java代碼 複製代碼
  1. public class InitializingCronTrigger extends CronTriggerBean implements Serializable {   
  2.      private ScheduleInfoManager scheduleInfoManager;   
  3.      // 設值注入,通過setter方法傳入被調用者的實例scheduleInfoManager  
  4.      public void setScheduleInfoManager(ScheduleInfoManager scheduleInfoManager){   
  5.          this.scheduleInfoManager = scheduleInfoManager;   
  6.          // 因爲在getCronExpressionFromDB使用到了scheduleInfoManager,所以  
  7.          // 必須上一行代碼設置scheduleInfoManager後進行  
  8. getCronExpressionFromDB   
  9.          String cronExpression = getCronExpressionFromDB ();   
  10.     // ①   
  11.          // 因爲extends CronTriggerBean ,此處調用父類方法初始化cronExpression  
  12.         setCronExpression(cronExpression);   
  13.                      // ②}  
  14.      private String getCronExpressionFromDB(){   
  15.          String sql="from ScheduleInfo scheduleInfo where   
  16.  1=1 ";   
  17.          sql=sql+" and scheduleInfo.infoId = '"+"1" + "'";   
  18.          List scheduleList = scheduleInfoManager.queryScheduleInListBySql(sql);   
  19.          ScheduleInfo scheduleInfo = (ScheduleInfo)scheduleList.get(0);   
  20.          String dbCronExpression = scheduleInfo.getCronExpression();   
  21.          return dbCronExpression;}……}  
Java代碼
  1. public class InitializingCronTrigger extends CronTriggerBean implements Serializable {  
  2.      private ScheduleInfoManager scheduleInfoManager;  
  3.      // 設值注入,通過setter方法傳入被調用者的實例scheduleInfoManager  
  4.      public void setScheduleInfoManager(ScheduleInfoManager scheduleInfoManager){  
  5.          this.scheduleInfoManager = scheduleInfoManager;  
  6.          // 因爲在getCronExpressionFromDB使用到了scheduleInfoManager,所以  
  7.          // 必須上一行代碼設置scheduleInfoManager後進行  
  8. getCronExpressionFromDB  
  9.          String cronExpression = getCronExpressionFromDB ();  
  10.     // ①  
  11.          // 因爲extends CronTriggerBean ,此處調用父類方法初始化cronExpression  
  12.         setCronExpression(cronExpression);  
  13.                      // ②}  
  14.      private String getCronExpressionFromDB(){  
  15.          String sql="from ScheduleInfo scheduleInfo where  
  16.  1=1 ";  
  17.          sql=sql+" and scheduleInfo.infoId = '"+"1" + "'";  
  18.          List scheduleList = scheduleInfoManager.queryScheduleInListBySql(sql);  
  19.          ScheduleInfo scheduleInfo = (ScheduleInfo)scheduleList.get(0);  
  20.          String dbCronExpression = scheduleInfo.getCronExpression();  
  21.          return dbCronExpression;}……}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章