扩展:spring3整合quartz2,实现动态添加、删除定时任务

一、Quartz简介  
Quartz大致可分为三个主要的核心:
    1、调度器Scheduler:是一个计划调度器容器,容器里面可以盛放众多的JobDetail和Trigger,当容器启动后,里面的每个JobDetail都会根据Trigger按部就班自动去执行 .
    2、任务Job:要执行的具体内容。JobDetail:具体的可执行的调度程序,包含了这个任务调度的方案和策略。
    3、触发器Trigger:调度参数的配置,什么时候去执行调度。
原理:
可以这么理解它的原理:调度器就相当于一个容器,装载着任务和触发器。任务和触发器又是绑定在一起的,然而一个任务可以对应多个触发器,但一个触发器却只能对应一个任务。当JobDetail和Trigger在scheduler容器上注册后,形成了装配好的任务作业(JobDetail和Trigger所组成的一对儿),就可以伴随容器启动而调度执行了。
二、与spring的整合
    本文的用的是quartz-2.2.1与spring-3.2.2。之所以在这里特别对版本作一下说明,是因为spring和quartz的整合对版本是有要求的。 spring3.1以下的版本必须使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然会出错。 原因主要是:spring对于quartz的支持实现,org.springframework.scheduling.quartz.CronTriggerBean继承了 org.quartz.CronTrigger,在quartz1.x系列中org.quartz.CronTrigger是个类,而在 quartz2.x系列中org.quartz.CronTrigger变成了接口,从而造成无法用spring的方式配置quartz的触发器 (trigger)。
spring中使用quartz有两种方式,具体请看 http://blog.csdn.net/liuxiao723846/article/details/46879077
三、动态整合
   上面的整合只能应付简单的需求,但很多时候我们遇到的是需要动态的添加、暂停、修改任务。而spring中所提供的定时任务组件却只能够通过修改xml中trigger的配置才能控制定时任务的时间以及任务的启用或停止,这在带给我们方便的同时也失去了动态配置任务的灵活性。
   所以我们就得换种方式来解决。把任务与cronExpression存放在数据库中,最大化减少xml配置,创建一个工厂类,在实际调用时把任务的相关信息通过参数方式传入,由该工厂类根据任务信息来具体执行需要的操作,从而方便我们的动态修改。

Maven

	<!-- quartz -->
	<dependency>
        	<groupId>org.quartz-scheduler</groupId>
        	<artifactId>quartz</artifactId>
        	<version>2.2.1</version>
    	</dependency>
		<dependency>
        	<groupId>org.quartz-scheduler</groupId>
        	<artifactId>quartz-jobs</artifactId>
        	<version>2.2.1</version>
    	</dependency>

1.spring配置(其实只要这一行足矣,去掉了原先"taskJob"、"myTrigger"等配置):
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" />
2. 任务执行入口( 就是在这里执行quartz容器中的任务的 ),实现Job接口,类似工厂类:
package com.es.quartz;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import com.es.entry.ExportTask;
import com.es.service.TaskExportService;
import com.es.utils.exception.BusinessException;
/**
 * 定时任务运行工厂类
 * @author Administrator
 *Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行, 如果定时任执行太长,会长时间占用资源,导致其它任务堵塞。
     1.在Spring中这时需要设置concurrent的值为false, 禁止并发执行。
     
      <property name="concurrent" value="true" />
     2.当不使用spring的时候就需要在Job的实现类上加@DisallowConcurrentExecution的注释
     
     设置@DisallowConcurrentExecution以后程序会等任务执行完毕以后再去执行,否则会在3秒时再启用新的线程执行
 */
@DisallowConcurrentExecution
public class QuartzJob implements Job {
      private Logger myLogger = LogManager. getLogger ( "QuartzJobFactory" );
      @Autowired
      private TaskExportService taskExportService ;
      @Override
      public void execute(JobExecutionContext context ) throws JobExecutionException {
           try {
              ExportTask task =   (ExportTask) context .getJobDetail().getJobDataMap().get( "task" );
//            context.getJobDetail().getJobDataMap().v
              myLogger .info( task .getName()+ ":任务成功运行" );
              if ( "exact" .equals( task .getSearchType())){
                    taskExportService .runTaskAutomaticForExact( task );
              }
           } catch (BusinessException e ) {
               e .printStackTrace();
           }
        myLogger .info( "任务成功运行完成" ); 
     }
}

3、 创建任务类。既然要动态修改任务,那任务就得保存在某个地方。一个po类
package com.es.entry;
public class ExportTask {
      private Integer id ;
      private String name ; //任务名
      private String export_cron ; // cron 表达式
      private String start_time ; //开始时间
      private String run_time ; //运行时长
      private Integer status ; //'状态(0:未运行,1:运行中,2:运行完成)
      private String file_url ; //文件地址
      private String params ; //查询参数
      private Integer type ; //调用类型(0:手动,1:周期)
      private String searchType ; //检索类型
      private Integer createUserId ; //创建人id
      public Integer getId() {
           return id ;
     }
      public void setId(Integer id ) {
           this . id = id ;
     }
      public String getName() {
           return name ;
     }
      public void setName(String name ) {
           this . name = name ;
     }
      public String getExport_cron() {
           return export_cron ;
     }
      public void setExport_cron(String export_cron ) {
           this . export_cron = export_cron ;
     }
      public String getStart_time() {
           return start_time ;
     }
      public void setStart_time(String start_time ) {
           this . start_time = start_time ;
     }
      public String getRun_time() {
           return run_time ;
     }
      public void setRun_time(String run_time ) {
           this . run_time = run_time ;
     }
      public Integer getStatus() {
           return status ;
     }
      public void setStatus(Integer status ) {
           this . status = status ;
     }
      public String getFile_url() {
           return file_url ;
     }
      public void setFile_url(String file_url ) {
           this . file_url = file_url ;
     }
      public String getParams() {
           return params ;
     }
      public void setParams(String params ) {
           this . params = params ;
     }
      public Integer getType() {
           return type ;
     }
      public void setType(Integer type ) {
           this . type = type ;
     }
      public String getSearchType() {
           return searchType ;
     }
      public void setSearchType(String searchType ) {
           this . searchType = searchType ;
     }
      public Integer getCreateUserId() {
           return createUserId ;
     }
      public void setCreateUserId(Integer createUserId ) {
           this . createUserId = createUserId ;
     }
}
4.在这里进行任务的增删改查
接口:
package com.es.quartz;

import java.util.List;
import com.es.entry.ExportTask;
import com.es.utils.exception.BusinessException;
public interface QuartzManager {
      /**
      * 向容器中添加任务
      * @param task
      * @throws BusinessException
      */
      public void addJob(ExportTask task ) throws BusinessException;
      /**
      * 从容器中删除任务
      * @param jobnames
      * @throws BusinessException
      */
      public void removeJob(List<String> jobnames ) throws BusinessException;
     
}
实现类:
package com.es.quartz.impl;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import com.es.entry.ExportTask;
import com.es.quartz.QuartzJob;
import com.es.quartz.QuartzManager;
import com.es.utils.exception.BusinessException;
@Component
public class QuartzManagerImpl implements QuartzManager {
      private Logger log = LogManager. getLogger ( "QuartzManagerImpl" );
      @Autowired
      private SchedulerFactoryBean schedulerFactoryBean ;
      @Override
      public void addJob (ExportTask task ) throws BusinessException {
           log .info( "addJob start:" +( task .getName()+ "@" + task .getId()));
          Scheduler scheduler = schedulerFactoryBean .getScheduler();
           //任务构建withIdentity:相当于给任务起了个名字
          JobDetail jobDetail =JobBuilder. newJob (QuartzJob. class ).withIdentity( new JobKey( task .getName()+ "@" + task .getId())).build();
          
           jobDetail .getJobDataMap().put( "task" , task );
           //表达式调度构建器
          CronScheduleBuilder scheduleBuilder = CronScheduleBuilder. cronSchedule ( task .getExport_cron());
           //按新的cronExpression表达式构建一个新的trigger:withIdentity:相当于给trigger起了个名字
          CronTrigger trigger = TriggerBuilder. newTrigger ().withSchedule( scheduleBuilder ).withIdentity( new TriggerKey( task .getName()+ "@" + task .getId())).build();
           try {
               scheduler .scheduleJob( jobDetail , trigger );
          } catch (SchedulerException e ) {
               throw new BusinessException( e , ( task .getName()+ "@" + task .getId())+ ":quartz添加job异常" );
          }
     }
      @Override
      public void removeJob (List<String> jobnames ) throws BusinessException {
           log .info( "removeJob start :" + jobnames .size());
           if ( null == jobnames || jobnames .isEmpty()){
               throw new BusinessException( jobnames + ":quartz删除job 参数异常" );
          }
          Scheduler scheduler = schedulerFactoryBean .getScheduler();
           try {
               for (String name : jobnames ){
                    scheduler .pauseTrigger( new TriggerKey( name )); // 停止触发器
                    scheduler .unscheduleJob( new TriggerKey( name )); //移除触发器
                    scheduler .deleteJob( new JobKey( name )); //删除任务 
              }
          } catch (SchedulerException e ) {
               throw new BusinessException( e , jobnames + ":quartz删除job异常" );
          }
     }
}
5.quartz的Job中注入spring对象
一般情况下,quartz的job中使用autowired注解注入的对象为空,这时候我们就要使用spring-quartz提供的AdaptableJobFactory类自定义一个类:
package com.es.quartz;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
/**
* 一般情况下,quartz的job中使用autowired注解注入的对象为空,
* 这时候我们就要使用spring-quartz提供的AdaptableJobFactory类。
* @author Administrator
*
*/
public class JobFactory extends AdaptableJobFactory {
      @Autowired
      private AutowireCapableBeanFactory capableBeanFactory;  
     @Override
     protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
          //调用父类的方法  
        Object jobInstance = super.createJobInstance(bundle);  
        //进行注入  
        capableBeanFactory.autowireBean(jobInstance);  
        return jobInstance;  
     }
}

然后将spring中配置改为如下:
<!-- quartz -->
      < bean id = "jobFactory" class = "com.es.quartz.JobFactory" ></ bean >
      < bean id = "schedulerFactoryBean" class = "org.springframework.scheduling.quartz.SchedulerFactoryBean" >
           < property name = "jobFactory" ref = "jobFactory" ></ property >
      </ bean >
这时候我们就可以在Job的实现类中使用autowired注入service对象了,如 QuartzJob类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值