SpringMvc + Quarzt 动态执行任务实现过程

原创 2015年07月07日 17:11:03

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.2.1。

本次遇到的情况是 关于N多个抓取任务的调度,并且由于各任务本身是有关联性,不易改造成标准的Jobs,并考虑到不去入侵和修改原来的任务方法,故期望运用Quartz按照Cron设定的时间去执行指定类和方法。

因为需要保存数据到数据库,设计了一个JavaBean来存储数据结构如下:

public class Quartz {
    /** 自动编号 */
    private Long              SCHEDULE_ID;
    /** 任务名称 */
    private String            NAME;
    /** 任务别名 */
    private String            ALIASNAME;
    /** 任务分组 */
    private String            GROUP;
    /** 任务执行类-全路径 */
    private String            CLASS;
    /** 任务执行类-方法 */
    private String            METHOD;
    /** 任务Cron表达式 */
    private String            CRON;
    /** 任务描述 */
    private String            DESC;
    private int               STATUS_ID;
    private Long              CREATETIME;
    private Long              UPDATETIME;
    private int               CREATEUSER;
    private int               UPDATEUSER;
}

Quartz 将作业划分为:执行器(JobDetail)、触发器(Trigger)、监听器(Listener),简略说就是执行器决定如何执行任务,触发器决定何时执行任务,监听器决定任务到达某状态如何操作。

Quartz典型的JobDetail是实现一个Job接口,然后新建一个触发器去执行该Job。

典型的Quartz应用一:

import java.util.Date;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.quartz.Job;  
import org.quartz.JobExecutionContext;  
import org.quartz.JobExecutionException;  

public class HelloJob implements Job {  

    private static Logger _log = LoggerFactory.getLogger(HelloJob.class);  

    public HelloJob() {  

    }  

    public void execute(JobExecutionContext context)  
        throws JobExecutionException {  

        _log.error(" 执行任务: " + new Date());  

    }  
}  

测试类

import static org.quartz.JobBuilder.newJob;  
import static org.quartz.TriggerBuilder.newTrigger;  
import static org.quartz.DateBuilder.*;  
import java.util.Date;  
import org.quartz.JobDetail;  
import org.quartz.Scheduler;  
import org.quartz.SchedulerFactory;  
import org.quartz.Trigger;  
import org.quartz.impl.StdSchedulerFactory;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
public class SimpleExample {  

    private static Logger log = LoggerFactory.getLogger(SimpleExample.class);  

    public void run() throws Exception {  

        // 通过SchedulerFactory获取一个调度器实例  
        SchedulerFactory sf = new StdSchedulerFactory();      

        Scheduler sched = sf.getScheduler();  

        Date runTime = evenMinuteDate(new Date());  

        // 通过过JobDetail封装HelloJob,同时指定Job在Scheduler中所属组及名称,这里,组名为group1,而名称为job1。  
        JobDetail job = newJob(HelloJob.class).withIdentity("job1", "group1").build();  

        // 创建一个SimpleTrigger实例,指定该Trigger在Scheduler中所属组及名称。  
        // 接着设置调度的时间规则.当前时间运行  
        Trigger trigger = newTrigger().withIdentity("trigger1", "group1").startAt(runTime).build();  

        // 注册并进行调度  
        sched.scheduleJob(job, trigger);  

        // 启动调度器  
        sched.start();  

        try {  
            //当前线程等待65秒  
            Thread.sleep(65L * 1000L);  
        } catch (Exception e) {  

        }  
        //调度器停止运行  
        sched.shutdown(true); 
        log.error("结束运行。。。。");      
    }  

    public static void main(String[] args) throws Exception {  
        SimpleExample example = new SimpleExample();  
        example.run();  
    }  
}  

典型的Quartz应用二:

<!-- 使用MethodInvokingJobDetailFactoryBean,任务类可以不实现Job接口,通过targetMethod指定调用方法-->
<bean id="taskJob" class="com.tyyd.dw.task.DataConversionTask"/>
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="group" value="job_work"/>
    <property name="name" value="job_work_name"/>
    <!--false表示等上一个任务执行完后再开启新的任务-->
    <property name="concurrent" value="false"/>
    <property name="targetObject">
        <ref bean="taskJob"/>
    </property>
    <property name="targetMethod">
        <value>execute</value>
    </property>
</bean>
<!--  调度触发器 -->
<bean id="myTrigger"
      class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="name" value="work_default_name"/>
    <property name="group" value="work_default"/>
    <property name="jobDetail">
        <ref bean="jobDetail" />
    </property>
    <property name="cronExpression">
        <value>0/5 * * * * ?</value>
    </property>
</bean>
<!-- 调度工厂 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="myTrigger"/>
        </list>
    </property>
</bean>

应用一是常见的java实现方式,没有使用Spring去管理Quartz对象,也反映Quartz可以脱离Spring独立执行。应用二是通过Spring配置文件实现执行实例化类的方法,但是把配置写在XML文件里面非常不方便修改。因此借鉴第二种方法实现Quartz的动态加载任务,同理也可实现增加、删除、暂停、启动、单次执行等功能。

考虑到Quartz调度工厂不需要多例,并且考虑注入的便捷性,在SpringMvc.xml文件里配置:

<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"/>

并将其注入到SchedulerJobService中。

package cn.focus.sh.core.quartz.service;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.stereotype.Service;

@Service
public class ScheduleJobService {

    @Autowired
    private Scheduler scheduler;

    private static Map<String,Quartz> QuartzMap = new ConcurrentHashMap<String,Quartz>();

    @Autowired
    SpringUtils utils;

    @Autowired
    private QuartzDao quartzDao;

    @PostConstruct
    public void init(){
        //从数据库初始化任务列表
        List<Quartz> list =  quartzDao.selectAll();

        for(Quartz quartz :list){
            run(quartz);
        }
    }
    public void run(Quartz quartz){
        MethodInvokingJobDetailFactoryBean bean =new MethodInvokingJobDetailFactoryBean();
        try {
            Class<?> loader = Class.forName(quartz.getCLASS());
            bean.setTargetObject(utils.getBean(loader));
            bean.setTargetClass(loader);
            bean.setTargetMethod(quartz.getMETHOD());
            bean.setGroup(quartz.getGROUP());
            bean.setName(quartz.getNAME());
            bean.setConcurrent(false);  
            bean.afterPropertiesSet();

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCRON());

            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartz.getNAME(), quartz.getGROUP())
                .withSchedule(scheduleBuilder).build();

            try {
                scheduler.scheduleJob(bean.getObject(), trigger);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
    }
}

CLASS cn.xxx.xxx.manager.xxxManager
METHOD getCount
CRON 0/10 * * * * ?

目前只实现了动态执行任务,同理可以实现动态暂停、删除、增加、修改等功能。

spring mvc quartz 实现动态定时任务管理

spring mvc quartz 实现动态定时任务管理
  • wujiaxin159
  • wujiaxin159
  • 2016年12月07日 17:26
  • 1453

spring+quartz,动态注册job

Spring+Quartz的整合有很多例子,此处不提整合; 若配置固定的job,常常使用MethodInvokingJobDetailFactoryBean,也不错, 可问题的根源在于 这个类没实...
  • monkeyking1987
  • monkeyking1987
  • 2014年12月26日 17:08
  • 4362

Spring4.0.6 +Quartz 2.2.1动态添加、修改、删除、关闭定时任务

说在前面:Spring Quartz动态添加、修改、删除、关闭定时任务, 无非就是将 《Spring task quartz 示例 一文中的Spring quartz示例 和 《Quartz ...
  • xlxxcc
  • xlxxcc
  • 2016年08月04日 14:17
  • 8911

springmvc中实现quartz定时任务[每分钟的第3秒执行]

  • 2015年06月24日 12:27
  • 5.02MB
  • 下载

Spring 整合 Quartz 实现动态定时任务(附demo)

最近项目中需要用到定时任务的功能,虽然Spring 也自带了一个轻量级的定时任务实现,但感觉不够灵活,功能也不够强大。在考虑之后,决定整合更为专业的Quartz来实现定时任务功能。普通定时任务首先,当...
  • u014723529
  • u014723529
  • 2016年05月01日 18:57
  • 41571

使用Spring Quartz做自动任务 启动和关闭

因开发需要做一个队自动任务的开关,网上的搜索的结果都不是很满意,考虑到spring本身使用的是单例模式,所以在springMVC中开发是最适合的。/** * 启动、关闭自动通过 * @auth...
  • yangxujia
  • yangxujia
  • 2015年11月13日 15:38
  • 7314

获取Quartz中Job的执行状态

StdSchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFac...
  • wangshuang1631
  • wangshuang1631
  • 2016年11月14日 16:50
  • 6229

Spring+Quartz 从数据库中获取定时任务和定时时间,动态实现对定时任务的增删改查

Spring+Quartz 从数据库中获取定时任务和定时时间,动态实现对定时任务的增删改查...
  • wwkms
  • wwkms
  • 2015年10月01日 23:42
  • 14994

Spring4+Springmvc+quartz实现多线程动态定时调度

scheduler定时调度系统是大多行业项目都需要的,传统的spring-job模式,个人感觉已经out了,因为存在很多的问题,特别是定时调度的追加、修改、删除等,需要修改xml,xml的配置生效无非...
  • qq_40949763
  • qq_40949763
  • 2017年11月07日 14:44
  • 268

Spring4+Quartz2集群动态创建任务

公司最近需要使用Quartz集群来实现任务的动态创建和删除,之前自己只是用过配置好的单机版的,而且是定时 执行的任务,正好借这个机会深入学习一下Quartz。      在正式开始之前,我们先来了解下...
  • zjx86320
  • zjx86320
  • 2016年08月29日 18:32
  • 6111
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:SpringMvc + Quarzt 动态执行任务实现过程
举报原因:
原因补充:

(最多只允许输入30个字)