Spring quartz定時器動態多任務實現

 項目中常常會碰到須要定時執行的任務,而且須要執行什麼任務,以及任務執行的時間都由用戶自定義的需求。quartz是比較經常使用的定時器工具,而且在spring框架中也已經作了很好的集成,因此在以spring+hibernate+struts的主流架構中,咱們能夠採用quartz來作定時器任務的解決方案,下面,咱們來看下如何在項目中使用quartz來作動態多任務定時器功能。html

      1.簡單單任務定時器的spring配置java

<!-- 配置定時任務,用於初始化定時器 -->  
    <bean id="InitJobDetail"  
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
        <property name="targetObject">  
            <ref bean="ReportJobTodo"/>  
        </property>  
        <property name="targetMethod">  
            <value>initJobTrigger</value>  
        </property>  
        <property name="concurrent" value ="false"/>    
    </bean>  
    <bean id="ReportJobTodo"  
        class="cn.com.gsoft.report.timetask.ReportJobTodo">  
    </bean>  
    <bean id="InitTrigger"  
        class="org.springframework.scheduling.quartz.CronTriggerBean">  
        <property name="jobDetail">  
            <ref bean="InitJobDetail"/>  
        </property>  
        <property name="cronExpression">  
            <value>* * * * * ?</value>  
        </property>  
    </bean>  
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
        <property name="triggers">  
            <list>  
                <ref local="InitTrigger"/>  
            </list>  
        </property>  
    </bean>  
<!-- 配置定時任務,用於初始化定時器 -->
 <bean id="InitJobDetail"
  class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
  <property name="targetObject">
   <ref bean="ReportJobTodo"/>
  </property>
  <property name="targetMethod">
   <value>initJobTrigger</value>
  </property>
     <property name="concurrent" value ="false"/> 
 </bean>
 <bean id="ReportJobTodo"
  class="cn.com.gsoft.report.timetask.ReportJobTodo">
 </bean>
 <bean id="InitTrigger"
  class="org.springframework.scheduling.quartz.CronTriggerBean">
  <property name="jobDetail">
   <ref bean="InitJobDetail"/>
  </property>
  <property name="cronExpression">
   <value>* * * * * ?</value>
  </property>
 </bean>
 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  <property name="triggers">
   <list>
    <ref local="InitTrigger"/>
   </list>
  </property>
 </bean>

說明:(1).InitJobDetail實例聲明瞭須要執行的任務。其中targetObject說明了須要執行的方法所在的實例對象,targetMethod說明了要執行的方法,concurrent用於說明多個任務是否同步執行。linux

         (2).InitTrigger聲明瞭一個觸發器。jobDetail屬性指明須要執行的任務,cronExpression聲明瞭該任務在何時執行,該表達式跟linux下的crontab定時程序中使用的表達式是同樣的,具體使用方法能夠參考文後的參考資料。spring

         (3).SchedulerFactoryBean中能夠定義多個觸發器,以實現多任務。數據庫

     2.動態多任務實現express

     實現方式:用戶在前臺自行維護任務列表和任務執行時間,後臺將任務執行時間解析成對應的cronexpression後與任務列表一塊兒保存到數據庫中。在服務器運行期間添加的任務經過驗證的(quartz會驗證cronexpression是否合法以及對應時間是否已通過期)將直接添加一個任務以及觸發器。若是服務器重啓,在項目啓動時讀取配置文件執行一次任務初始化動做,保證經過驗證的任務能在觸發隊列中,並在到達指定時間時可以觸發執行。服務器

     (1).在applicationContext.xml中添加如1中的配置,配置的任務只執行一次後即被禁用,initJobTrigger方法以下:架構

/**  
     * 容器啓動時初始化任務  
     * @throws SchedulerException   
     * @throws ParseException   
     */  
    public void initJobTrigger() throws SchedulerException, ParseException{   
           
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();   
        Scheduler scheduler = schedulerFactory.getScheduler();   
        //獲取任務列表的HQL語句   
        String hql = "from ReportJob r where r.enabled = ?";   
        List list = baseDao.selectByHql(hql, new Object[]{ReportJobConstants.TRUE_STRING});   
        if(null != list && list.size() > 0){   
            Iterator ite = list.iterator();   
            while(ite.hasNext()){   
                //任務對象   
                ReportJob rj = (ReportJob)ite.next();   
                //定時表達式   
                String cronExpression = rj.getCronExpression();   
                //新建任務,任務組爲默認的Scheduler.DEFAULT_GROUP,須要執行的任務類爲ReportJobTodo.class   
                JobDetail jobDetail =  new JobDetail("reportJob_" + rj.getGuId(), Scheduler.DEFAULT_GROUP,   
                            ReportJobTodo.class);   
                //新建觸發器,觸發器爲默認的Scheduler.DEFAULT_GROUP   
                CronTrigger cronTrigger = new CronTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);   
                //爲觸發器設置定時表達式   
                cronTrigger.setCronExpression(cronExpression);   
                try{   
                //啓動新增定時器任務    
                scheduler.scheduleJob(jobDetail, cronTrigger);   
                }catch(SchedulerException e){   
                    //啓動驗證失敗,設置任務標記爲禁用   
                    e.printStackTrace();   
                    rj.setEnabled(ReportJobConstants.FALSE_STRING);   
                    baseDao.updateObject(rj);   
                }   
            }   
        }   
        //初始化任務只須要執行一次,執行一次後移除初始化觸發器   
        scheduler.unscheduleJob("InitTrigger", Scheduler.DEFAULT_GROUP);   
        //任務啓動   
        scheduler.start();   
    }  
/**
  * 容器啓動時初始化任務
  * @throws SchedulerException 
  * @throws ParseException 
  */
 public void initJobTrigger() throws SchedulerException, ParseException{
  
  SchedulerFactory schedulerFactory = new StdSchedulerFactory();
  Scheduler scheduler = schedulerFactory.getScheduler();
  //獲取任務列表的HQL語句
  String hql = "from ReportJob r where r.enabled = ?";
  List list = baseDao.selectByHql(hql, new Object[]{ReportJobConstants.TRUE_STRING});
  if(null != list && list.size() > 0){
   Iterator ite = list.iterator();
   while(ite.hasNext()){
    //任務對象
    ReportJob rj = (ReportJob)ite.next();
    //定時表達式
    String cronExpression = rj.getCronExpression();
    //新建任務,任務組爲默認的Scheduler.DEFAULT_GROUP,須要執行的任務類爲ReportJobTodo.class
    JobDetail jobDetail =  new JobDetail("reportJob_" + rj.getGuId(), Scheduler.DEFAULT_GROUP,
       ReportJobTodo.class);
    //新建觸發器,觸發器爲默認的Scheduler.DEFAULT_GROUP
    CronTrigger cronTrigger = new CronTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);
    //爲觸發器設置定時表達式
    cronTrigger.setCronExpression(cronExpression);
    try{
    //啓動新增定時器任務 
    scheduler.scheduleJob(jobDetail, cronTrigger);
    }catch(SchedulerException e){
     //啓動驗證失敗,設置任務標記爲禁用
     e.printStackTrace();
     rj.setEnabled(ReportJobConstants.FALSE_STRING);
     baseDao.updateObject(rj);
    }
   }
  }
  //初始化任務只須要執行一次,執行一次後移除初始化觸發器
  scheduler.unscheduleJob("InitTrigger", Scheduler.DEFAULT_GROUP);
  //任務啓動
  scheduler.start();
 }

(2).全部的觸發器執行的任務類均爲ReportJobTodo.class,ReportJobTodo須要實現接口:org.quartz.Job中的方法execute方法,參考代碼以下:app

/**  
     * 報表生成任務  
     */  
    public void execute(JobExecutionContext je) throws JobExecutionException {   
        //獲取觸發器名稱   
        String triggerName = je.getTrigger().getName();   
        //根據觸發器名稱獲得對應的任務Id   
        Long reportJobGuId = Long.valueOf(triggerName.split("_")[1]);   
        //獲取任務   
        ReportJob rj = (ReportJob)baseDao.loadObject(ReportJob.class, reportJobGuId);   
        //獲取任務細節列表   
        String hql = "from ReportJobDetail t where reportJobGuId = ?";   
        List list = baseDao.selectByHql(hql, new Object[]{reportJobGuId});   
        if(null != list && list.size() > 0){   
            Iterator ite = list.iterator();   
            while(ite.hasNext()){   
                //任務細節對象   
                ReportJobDetail rjd = (ReportJobDetail)ite.next();   
                //根據獲取的任務對象來作具體操做   
                //something to do   
            }   
        }   
        //若是有須要,能夠將執行過的任務移除   
        //try {   
        //  je.getScheduler().unscheduleJob(triggerName, je.getTrigger().getGroup());   
        //} catch (SchedulerException e) {   
        //  throw new BusinessException(e.getMessage());   
        //}   
    }  
/**
  * 報表生成任務
  */
 public void execute(JobExecutionContext je) throws JobExecutionException {
  //獲取觸發器名稱
  String triggerName = je.getTrigger().getName();
  //根據觸發器名稱獲得對應的任務Id
  Long reportJobGuId = Long.valueOf(triggerName.split("_")[1]);
  //獲取任務
  ReportJob rj = (ReportJob)baseDao.loadObject(ReportJob.class, reportJobGuId);
  //獲取任務細節列表
  String hql = "from ReportJobDetail t where reportJobGuId = ?";
  List list = baseDao.selectByHql(hql, new Object[]{reportJobGuId});
  if(null != list && list.size() > 0){
   Iterator ite = list.iterator();
   while(ite.hasNext()){
    //任務細節對象
    ReportJobDetail rjd = (ReportJobDetail)ite.next();
    //根據獲取的任務對象來作具體操做
    //something to do
   }
  }
  //若是有須要,能夠將執行過的任務移除
  //try {
  // je.getScheduler().unscheduleJob(triggerName, je.getTrigger().getGroup());
  //} catch (SchedulerException e) {
  // throw new BusinessException(e.getMessage());
  //}
 }

(3).對於每個任務提供啓用和禁用的功能,啓用時將任務加入到任務執行列表中,禁用時移除:框架

/**  
     * 啓動或禁止任務觸發器  
     * @param condition  
     * @throws SchedulerException   
     * @throws ParseException   
     */  
    public static void enableTrigger(ReportJobCondition condition) throws SchedulerException, ParseException{   
        //獲取任務對象的HQL語句   
        String hql = "from ReportJob t where t.guId = ?";   
        List list = dao.selectByHql(hql, new Object[]{condition.getObjGuId()});   
        if(null != list && list.size() > 0){   
            //任務對象   
            ReportJob rj = (ReportJob)list.get(0);   
            //定時器表達式   
            String cronExpression = rj.getCronExpression();   
            //獲取調度工廠對象   
            SchedulerFactory schedulerFactory = new StdSchedulerFactory();   
            Scheduler scheduler = schedulerFactory.getScheduler();   
               
            //啓動任務   
            if(ReportJobConstants.TRUE_STRING.equals(condition.getEnabled())){   
                //添加任務   
                JobDetail jobDetail = new JobDetail("reportJob_" + rj.getGuId(), Scheduler.DEFAULT_GROUP,   
                            ReportJobTodo.class);   
                //添加觸發器   
                CronTrigger cronTrigger = new CronTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);   
                //設置定時表達式   
                cronTrigger.setCronExpression(cronExpression);   
                //啓動任務   
                scheduler.scheduleJob(jobDetail, cronTrigger);   
                rj.setEnabled(ReportJobConstants.TRUE_STRING);   
                dao.updateObject(rj);   
                dao.flush();   
            }else{   
                //移除觸發器   
                CronTrigger cronTrigger = (CronTrigger)scheduler.getTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);   
                if(null != cronTrigger){   
                    scheduler.unscheduleJob(cronTrigger.getName(), Scheduler.DEFAULT_GROUP);   
                }   
                rj.setEnabled(ReportJobConstants.FALSE_STRING);   
                dao.updateObject(rj);   
                dao.flush();   
            }   
            //調度器啓動   
            scheduler.start();   
        }   
    }  
/**
  * 啓動或禁止任務觸發器
  * @param condition
  * @throws SchedulerException 
  * @throws ParseException 
  */
 public static void enableTrigger(ReportJobCondition condition) throws SchedulerException, ParseException{
  //獲取任務對象的HQL語句
  String hql = "from ReportJob t where t.guId = ?";
  List list = dao.selectByHql(hql, new Object[]{condition.getObjGuId()});
  if(null != list && list.size() > 0){
   //任務對象
   ReportJob rj = (ReportJob)list.get(0);
   //定時器表達式
   String cronExpression = rj.getCronExpression();
   //獲取調度工廠對象
   SchedulerFactory schedulerFactory = new StdSchedulerFactory();
   Scheduler scheduler = schedulerFactory.getScheduler();
   
   //啓動任務
   if(ReportJobConstants.TRUE_STRING.equals(condition.getEnabled())){
    //添加任務
    JobDetail jobDetail = new JobDetail("reportJob_" + rj.getGuId(), Scheduler.DEFAULT_GROUP,
       ReportJobTodo.class);
    //添加觸發器
    CronTrigger cronTrigger = new CronTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);
    //設置定時表達式
    cronTrigger.setCronExpression(cronExpression);
    //啓動任務
    scheduler.scheduleJob(jobDetail, cronTrigger);
    rj.setEnabled(ReportJobConstants.TRUE_STRING);
    dao.updateObject(rj);
    dao.flush();
   }else{
    //移除觸發器
    CronTrigger cronTrigger = (CronTrigger)scheduler.getTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);
    if(null != cronTrigger){
     scheduler.unscheduleJob(cronTrigger.getName(), Scheduler.DEFAULT_GROUP);
    }
    rj.setEnabled(ReportJobConstants.FALSE_STRING);
    dao.updateObject(rj);
    dao.flush();
   }
   //調度器啓動
   scheduler.start();
  }
 }

參考資料:

1.cronExpression介紹:http://en.wikipedia.org/wiki/CRON_expression

http://jlusdy.javaeye.com/blog/87044

2.quartz官方文檔:http://www.quartz-scheduler.org/docs/index.html

相關文章
相關標籤/搜索