项目ITP(六) spring4.0 整合 Quartz 实现动态任务调度

来源:互联网 发布:vmp脱壳软件 编辑:程序博客网 时间:2024/06/05 08:18

前言

  系列文章:[传送门]

  项目需求:

     http://www.cnblogs.com/Alandre/p/3733249.html

     上一博客写的是基本调度,后来这只能用于,像每天定个时间 进行数据库备份。但是,远远不能在上次的需求上实现。所以需要实现spring4.0 整合 Quartz 实现动态任务调度。

 

正文 

  spring4.0 整合 Quartz 实现任务调度。这真是期末项目的最后一篇,剩下到暑假吧。

    Quartz 介绍

    Quartz is a full-featured, open source job scheduling service that can be integrated with, or used along side virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; 
    Quartz框架是一个全功能、开源的任务调度服务,可以集成几乎任何的java应用程序—从小的单片机系统到大型的电子商务系统。Quartz可以执行上千上万的任务调度。
 
   核心概念
     Quartz核心的概念:scheduler任务调度、Job任务、Trigger触发器、JobDetail任务细节
     相关文档:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/quick-start

回顾

  上次我们配置了

复制代码
<!--Quartz-->                <!-- 集成方式:JobDetailFactoryBean,并且任务类需要继承QuartzJobBean-->    <!-- 定义jobDetail -->    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">        <!-- durability 表示任务完成之后是否依然保留到数据库,默认false   -->        <property name="durability" value="true" />          <!--     目标类  /wmuitp/src/test/SpringQuartz.java-->        <property name="jobClass" value="test.SpringQuartzTest"></property>                   <!--  在这个例子中,jobDataAsMap没有用,此目标类中接受的参数 ,若参数为service,则可以在此进行参数配置,类似struts2 -->           <!--        <property name="jobDataAsMap">              <map>                  <entry key="service"><value>simple is the beat</value></entry>              </map>          </property>            -->    </bean>        <!-- 定义simpleTrigger触发器 -->    <!--         <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">        <property name="jobDetail" ref="jobDetail"></property>        <property name="repeatCount">            <value>8</value>        </property>        <property name="repeatInterval">            <value>1000</value>        </property>        <property name="startDelay">            <value>4</value>        </property>    </bean>     -->        <!-- 另一种触发器是CornTrigger -->     <bean id="cornTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">       <property name="jobDetail" ref="jobDetail"/>       <!-- 每个10秒触发 -->       <property name="cronExpression" value="0/10 * * * * ?"/>    </bean>         <!-- 定义核心调度器 -->    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">      <property name="triggers">        <ref bean="cornTrigger"/>      </property>    </bean>
复制代码

  #spring实现quartz的方式,先看一下上面配置文件中定义的jobDetail。在Quartz 2.x版本中JobDetail已经是一个接口,Spring是通过将其转换为MethodInvokingJob或StatefulMethodInvokingJob类型来实现的。

 

  这是文档中的源码:

复制代码
/** * This implementation applies the passed-in job data map as bean property * values, and delegates to <code>executeInternal</code> afterwards. * @see #executeInternal */public final void execute(JobExecutionContext context) throws JobExecutionException {    try {        // Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...        Scheduler scheduler = (Scheduler) ReflectionUtils.invokeMethod(getSchedulerMethod, context);        Map mergedJobDataMap = (Map) ReflectionUtils.invokeMethod(getMergedJobDataMapMethod, context);         BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);        MutablePropertyValues pvs = new MutablePropertyValues();        pvs.addPropertyValues(scheduler.getContext());        pvs.addPropertyValues(mergedJobDataMap);        bw.setPropertyValues(pvs, true);    }    catch (SchedulerException ex) {        throw new JobExecutionException(ex);    }    executeInternal(context);} /** * Execute the actual job. The job data map will already have been * applied as bean property values by execute. The contract is * exactly the same as for the standard Quartz execute method. * @see #execute */protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException;
复制代码

 

  MethodInvokingJobDetailFactoryBean中的源码:

复制代码
public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException {    prepare();     // Use specific name if given, else fall back to bean name.    String name = (this.name != null ? this.name : this.beanName);     // Consider the concurrent flag to choose between stateful and stateless job.    Class jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);     // Build JobDetail instance.    if (jobDetailImplClass != null) {        // Using Quartz 2.0 JobDetailImpl class...        this.jobDetail = (JobDetail) BeanUtils.instantiate(jobDetailImplClass);        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this.jobDetail);        bw.setPropertyValue("name", name);        bw.setPropertyValue("group", this.group);        bw.setPropertyValue("jobClass", jobClass);        bw.setPropertyValue("durability", true);        ((JobDataMap) bw.getPropertyValue("jobDataMap")).put("methodInvoker", this);    }    else {        // Using Quartz 1.x JobDetail class...        this.jobDetail = new JobDetail(name, this.group, jobClass);        this.jobDetail.setVolatility(true);        this.jobDetail.setDurability(true);        this.jobDetail.getJobDataMap().put("methodInvoker", this);    }     // Register job listener names.    if (this.jobListenerNames != null) {        for (String jobListenerName : this.jobListenerNames) {            if (jobDetailImplClass != null) {                throw new IllegalStateException("Non-global JobListeners not supported on Quartz 2 - " +                        "manually register a Matcher against the Quartz ListenerManager instead");            }            this.jobDetail.addJobListener(jobListenerName);        }    }     postProcessJobDetail(this.jobDetail);}
复制代码

 

  #既然知道了其所以然,我们就可以真正实战了。

实战 

  听我慢慢道来

减少spring的配置文件

  为了实现一个定时任务,spring的配置代码太多了。动态配置需要们手动来搞。这里我们只需要这要配置即可:

    <!-- quartz配置  动态配置所以我们将 Factory 作为一个service一样的接口 QuartzJobFactory.java-->    <!-- 调度工厂 -->    <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">    </bean>

 

Job实现类

  在这里我把它看作工厂类:

复制代码
package test;import org.quartz.DisallowConcurrentExecution;import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;@DisallowConcurrentExecutionpublic class QuartzJobFactoryImpl implements Job {    @Override    public void execute(JobExecutionContext context) throws JobExecutionException    {        System.out.println("任务成功运行");        ScheduleJob scheduleJob = (ScheduleJob)context.getMergedJobDataMap().get("scheduleJob");        System.out.println("任务名称 = [" + scheduleJob.getJobName() + "]");    }
}
复制代码

 

任务对应实体类

复制代码
package test;public class ScheduleJob{     /** 任务id **/    private String jobId;     /** 任务名称 **/    private String jobName;     /** 任务分组 **/    private String jobGroup;     /** 任务状态 0禁用 1启用 2删除**/    private String jobStatus;     /** 任务运行时间表达式 **/    private String cronExpression;     /** 任务描述 **/    private String desc;    public String getJobId()    {        return jobId;    }    public void setJobId(String jobId)    {        this.jobId = jobId;    }    public String getJobName()    {        return jobName;    }    public void setJobName(String jobName)    {        this.jobName = jobName;    }    public String getJobGroup()    {        return jobGroup;    }    public void setJobGroup(String jobGroup)    {        this.jobGroup = jobGroup;    }    public String getJobStatus()    {        return jobStatus;    }    public void setJobStatus(String jobStatus)    {        this.jobStatus = jobStatus;    }    public String getCronExpression()    {        return cronExpression;    }    public void setCronExpression(String cronExpression)    {        this.cronExpression = cronExpression;    }    public String getDesc()    {        return desc;    }    public void setDesc(String desc)    {        this.desc = desc;    }        }
复制代码

 

 

下面我们就来测试下:

Controller 测试代码:

复制代码
  @RequestMapping(value = "/quartz")    public ModelAndView quartz() throws SchedulerException     {                    //schedulerFactoryBean 由spring创建注入        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");          System.out.println(ctx);        Scheduler scheduler = (Scheduler)ctx.getBean("schedulerFactoryBean");                System.out.println(scheduler);        //这里获取任务信息数据        List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();                for (int i = 0; i < 3; i++) {            ScheduleJob job = new ScheduleJob();            job.setJobId("10001" + i);            job.setJobName("JobName_" + i);            job.setJobGroup("dataWork");            job.setJobStatus("1");            job.setCronExpression("0/5 * * * * ?");            job.setDesc("数据导入任务");            jobList.add(job);        }        for (ScheduleJob job : jobList) {                     TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());                     //获取trigger,即在spring配置文件中定义的 bean id="myTrigger"            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);            //不存在,创建一个            if (null == trigger) {                JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactoryImpl.class)                    .withIdentity(job.getJobName(), job.getJobGroup()).build();                jobDetail.getJobDataMap().put("scheduleJob", job);                         //表达式调度构建器                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job                    .getCronExpression());                         //按新的cronExpression表达式构建一个新的trigger                trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup()).withSchedule(scheduleBuilder).build();                scheduler.scheduleJob(jobDetail, trigger);            } else {                // Trigger已存在,那么更新相应的定时设置                //表达式调度构建器                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job                    .getCronExpression());                         //按新的cronExpression表达式重新构建trigger                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)                    .withSchedule(scheduleBuilder).build();                         //按新的trigger重新设置job执行                scheduler.rescheduleJob(triggerKey, trigger);            }        }                ModelAndView mav = new ModelAndView(AdminWebConstant.ADMIN_LOGIN_VIEW);        return mav;    }
复制代码

 

 #后面这块应该会进一步整理。到时候 会出个更详细的。期待吧

 

测试结果:

总结

  spring quartz

  

0 0