文档章节

Spring quartz定时器动态多任务实现

凯文加内特
 凯文加内特
发布于 2015/06/27 11:39
字数 1823
阅读 2626
收藏 10

 项目中经常会碰到需要定时执行的任务,并且需要执行什么任务,以及任务执行的时间都由用户自定义的需求。quartz是比较常用的定时器工具,并且在spring框架中也已经做了很好的集成,所以在以spring+hibernate+struts的主流架构中,我们可以采用quartz来做定时器任务的解决方案,下面,我们来看下如何在项目中使用quartz来做动态多任务定时器功能。

      1.简单单任务定时器的spring配置

<!-- 配置定时任务,用于初始化定时器 -->  
    <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用于说明多个任务是否同步执行。

         (2).InitTrigger声明了一个触发器。jobDetail属性指明需要执行的任务,cronExpression声明了该任务在什么时候执行,该表达式跟linux下的crontab定时程序中使用的表达式是一样的,具体使用方法可以参考文后的参考资料。

         (3).SchedulerFactoryBean中可以定义多个触发器,以实现多任务。

     2.动态多任务实现

     实现方式:用户在前台自行维护任务列表和任务执行时间,后台将任务执行时间解析成对应的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方法,参考代码如下:

/**  
     * 报表生成任务  
     */  
    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


本文转载自:http://blog.csdn.net/fuxiaohui/article/details/6287069

共有 人打赏支持
凯文加内特
粉丝 337
博文 672
码字总数 94457
作品 0
青岛
后端工程师
私信 提问
分布式定时任务框架---Uncode Schedule

分布式定时任务框架---Uncode Schedule rabbitGYK 关注 2016.11.27 20:36* 字数 1446 阅读 7141评论 5喜欢 36赞赏 1 博客原文 作为一个支付公司的项目组,经常会有很多对账功能(签约对账、支...

晨猫
11/02
0
0
[spring-framework] 定时器配置和使用(补充篇)

前面已经介绍过spring中定时器的配置和使用了,但楼主在使用spring 4.2.0包时才发现,原来新版的spring中对定时器的配置和老版本的配置略有不同。 spring 3.8.0定时器配置详见: spring-fram...

LSantorini
2015/11/22
0
0
Spring Cloud 2.x系列之springboot集成quartz

java设计模式之观察者模式 一大波视频分享 Mysql代理中间件Atlas安装和配置 在做项目时有时候会有定时器任务的功能,比如某某时间应该做什么,多少秒应该怎么样之类的。定时任务常用的业务场...

技术小能手
10/15
0
0
spring+quartz 定时器使用

项目使用:spring+springMVC+JPA+Maven 1、在pom.xml中引用quartz的jar包 <!-- quartz --><dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version......

杀丶破狼
2015/10/13
103
1
项目ITP(六) spring4.0 整合 Quartz 实现动态任务调度

2014-05-18 12:51 by Jeff Li 前言   系列文章:[传送门]   项目需求:      http://www.cnblogs.com/Alandre/p/3733249.html      上一博客写的是基本调度,后来这只能用于,...

泥沙砖瓦浆木匠
2014/05/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

day150-2018-11-17-英语流利阅读-待学习

歪果仁也疯狂:海外版抖音的征途 毛西 2018-11-17 1.今日导读 海外版抖音 TikTok 于 2017 年 5 月上线海外,至今覆盖全球 150 多个国家和地区,月活跃用户数已突破 5 亿。然而,“出海”的抖...

飞鱼说编程
今天
4
0
分布式学习最佳实践:从分布式系统的特征开始(附思维导图)

什么是分布式系统 回到顶部   分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法...

dragon_tech
今天
4
0
TOKEN设计

TOKEN设计 Api_Token 首先需要知道API是什么? API(Application Programming Interface)即应用程序接口。你可以认为 API 是一个软件组件或是一个 Web 服务与外界进行的交互的接口。而我们在...

DrChenXX
今天
3
0
浅谈“李氏代换”——从纪念金庸和斯坦李说起

李氏代换(LSP)简介 李氏代换是软件设计的一个原则,又名依赖倒转原则或依赖倒置原则,其衍生原则有接口分离原则等。该原则由Barbara Liskov于1988年提出。 该原则指出,程序中高级别的元素...

SamYjy
今天
33
0
JavaScript实现在线websocket WSS测试工具 -toolfk程序员工具网

本文要推荐的[ToolFk]是一款程序员经常使用的线上免费测试工具箱,ToolFk 特色是专注于程序员日常的开发工具,不用安装任何软件,只要把内容贴上按一个执行按钮,就能获取到想要的内容结果。T...

toolfk
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部