分布式任务调度平台,spring+quartz 借鉴

可参考:https://github.com/xuxueli/xxl-job

http://www.xuxueli.com/xxl-job/#/


在实际项目应用中经常会用到定时任务,可以通过quartz和spring的简单配置即可完成,但如果要改变任务的执行时间、频率,废弃任务等就需要改变配置甚至代码需要重启服务器,这里介绍一下如何通过quartz与spring的组合实现动态的改变定时任务的状态的一个实现。

参考文章:http://www.meiriyouke.net/?p=82

本文章适合对quartz和spring有一定了解的读者。
spring版本为3.2  quartz版本为2.2.1  如果使用了quartz2.2.1 则spring版本需3.1以上
1.
spring中引入注册bean

 

Xml代码   收藏代码
  1. <bean id="schedulerFactoryBean"  
  2.         class="org.springframework.scheduling.quartz.SchedulerFactoryBean" />  
 

 

为什么要与spring结合?
与spring结合可以使用spring统一管理quartz中任务的生命周期,使得web容器关闭时所有的任务一同关闭。如果不用spring管理可能会出现web容器关闭而任务仍在继续运行的情况,不与spring结合的话要自己控制任务在容器关闭时一起关闭。
2.创建保存计划任务信息的实体类

Java代码   收藏代码
  1. /** 
  2.  *  
  3. * @Description: 计划任务信息 
  4. * @author snailxr 
  5. * @date 2014年4月24日 下午10:49:43 
  6.  */  
  7. public class ScheduleJob {  
  8.   
  9.     public static final String STATUS_RUNNING = "1";  
  10.     public static final String STATUS_NOT_RUNNING = "0";  
  11.     public static final String CONCURRENT_IS = "1";  
  12.     public static final String CONCURRENT_NOT = "0";  
  13.     private Long jobId;  
  14.   
  15.     private Date createTime;  
  16.   
  17.     private Date updateTime;  
  18.     /** 
  19.      * 任务名称 
  20.      */  
  21.     private String jobName;  
  22.     /** 
  23.      * 任务分组 
  24.      */  
  25.     private String jobGroup;  
  26.     /** 
  27.      * 任务状态 是否启动任务 
  28.      */  
  29.     private String jobStatus;  
  30.     /** 
  31.      * cron表达式 
  32.      */  
  33.     private String cronExpression;  
  34.     /** 
  35.      * 描述 
  36.      */  
  37.     private String description;  
  38.     /** 
  39.      * 任务执行时调用哪个类的方法 包名+类名 
  40.      */  
  41.     private String beanClass;  
  42.     /** 
  43.      * 任务是否有状态 
  44.      */  
  45.     private String isConcurrent;  
  46.     /** 
  47.      * spring bean 
  48.      */  
  49.     private String springId;  
  50.     /** 
  51.      * 任务调用的方法名 
  52.      */  
  53.     private String methodName;  
  54.   
  55.     //get  set.......  
  56. }  

 该实体类与数据库中的表对应,在数据库中存储多个计划任务。

  注意:jobName 跟 groupName的组合应该是唯一的,beanClass springId至少有一个

 

在项目启动时运行以下代码:

 

Java代码   收藏代码
  1. public void init() throws Exception {  
  2.   
  3.         Scheduler scheduler = schedulerFactoryBean.getScheduler();  
  4.   
  5.         // 这里从数据库中获取任务信息数据  
  6.         List<ScheduleJob> jobList = scheduleJobMapper.getAll();  
  7.       
  8.         for (ScheduleJob job : jobList) {  
  9.             addJob(job);  
  10.         }  
  11.     }  

 

Java代码   收藏代码
  1. /** 
  2.      * 添加任务 
  3.      *  
  4.      * @param scheduleJob 
  5.      * @throws SchedulerException 
  6.      */  
  7.     public void addJob(ScheduleJob job) throws SchedulerException {  
  8.         if (job == null || !ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) {  
  9.             return;  
  10.         }  
  11.   
  12.         Scheduler scheduler = schedulerFactoryBean.getScheduler();  
  13.         log.debug(scheduler + ".......................................................................................add");  
  14.         TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());  
  15.   
  16.         CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);  
  17.   
  18.         // 不存在,创建一个  
  19.         if (null == trigger) {  
  20.             Class clazz = ScheduleJob.CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class : QuartzJobFactoryDisallowConcurrentExecution.class;  
  21.   
  22.             JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build();  
  23.   
  24.             jobDetail.getJobDataMap().put("scheduleJob", job);  
  25.   
  26.             CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());  
  27.   
  28.             trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup()).withSchedule(scheduleBuilder).build();  
  29.   
  30.             scheduler.scheduleJob(jobDetail, trigger);  
  31.         } else {  
  32.             // Trigger已存在,那么更新相应的定时设置  
  33.             CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());  
  34.   
  35.             // 按新的cronExpression表达式重新构建trigger  
  36.             trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();  
  37.   
  38.             // 按新的trigger重新设置job执行  
  39.             scheduler.rescheduleJob(triggerKey, trigger);  
  40.         }  
  41.     }  

 看到代码第20行根据scheduleJob类中CONCURRENT_IS来判断任务是否有状态。来给出不同的Job实现类

 

Java代码   收藏代码
  1. /** 
  2.  *  
  3.  * @Description: 若一个方法一次执行不完下次轮转时则等待改方法执行完后才执行下一次操作 
  4.  * @author snailxr 
  5.  * @date 2014年4月24日 下午5:05:47 
  6.  */  
  7. @DisallowConcurrentExecution  
  8. public class QuartzJobFactoryDisallowConcurrentExecution implements Job {  
  9.     public final Logger log = Logger.getLogger(this.getClass());  
  10.   
  11.     @Override  
  12.     public void execute(JobExecutionContext context) throws JobExecutionException {  
  13.         ScheduleJob scheduleJob = (ScheduleJob) context.getMergedJobDataMap().get("scheduleJob");  
  14.         TaskUtils.invokMethod(scheduleJob);  
  15.   
  16.     }  
  17. }  

 

Java代码   收藏代码
  1. /** 
  2.  *  
  3.  * @Description: 计划任务执行处 无状态 
  4.  * @author snailxr 
  5.  * @date 2014年4月24日 下午5:05:47 
  6.  */  
  7. public class QuartzJobFactory implements Job {  
  8.     public final Logger log = Logger.getLogger(this.getClass());  
  9.   
  10.     @Override  
  11.     public void execute(JobExecutionContext context) throws JobExecutionException {  
  12.         ScheduleJob scheduleJob = (ScheduleJob) context.getMergedJobDataMap().get("scheduleJob");  
  13.         TaskUtils.invokMethod(scheduleJob);  
  14.     }  
  15. }  

 

真正执行计划任务的代码就在TaskUtils.invokMethod(scheduleJob)里面

通过scheduleJob的beanClass或springId通过反射或spring来获得需要执行的类,通过methodName来确定执行哪个方法

Java代码   收藏代码
  1. public class TaskUtils {  
  2.     public final static Logger log = Logger.getLogger(TaskUtils.class);  
  3.   
  4.     /** 
  5.      * 通过反射调用scheduleJob中定义的方法 
  6.      *  
  7.      * @param scheduleJob 
  8.      */  
  9.     public static void invokMethod(ScheduleJob scheduleJob) {  
  10.         Object object = null;  
  11.         Class clazz = null;  
  12.                 //springId不为空先按springId查找bean  
  13.         if (StringUtils.isNotBlank(scheduleJob.getSpringId())) {  
  14.             object = SpringUtils.getBean(scheduleJob.getSpringId());  
  15.         } else if (StringUtils.isNotBlank(scheduleJob.getBeanClass())) {  
  16.             try {  
  17.                 clazz = Class.forName(scheduleJob.getBeanClass());  
  18.                 object = clazz.newInstance();  
  19.             } catch (Exception e) {  
  20.                 // TODO Auto-generated catch block  
  21.                 e.printStackTrace();  
  22.             }  
  23.   
  24.         }  
  25.         if (object == null) {  
  26.             log.error("任务名称 = [" + scheduleJob.getJobName() + "]---------------未启动成功,请检查是否配置正确!!!");  
  27.             return;  
  28.         }  
  29.         clazz = object.getClass();  
  30.         Method method = null;  
  31.         try {  
  32.             method = clazz.getDeclaredMethod(scheduleJob.getMethodName());  
  33.         } catch (NoSuchMethodException e) {  
  34.             log.error("任务名称 = [" + scheduleJob.getJobName() + "]---------------未启动成功,方法名设置错误!!!");  
  35.         } catch (SecurityException e) {  
  36.             // TODO Auto-generated catch block  
  37.             e.printStackTrace();  
  38.         }  
  39.         if (method != null) {  
  40.             try {  
  41.                 method.invoke(object);  
  42.             } catch (IllegalAccessException e) {  
  43.                 // TODO Auto-generated catch block  
  44.                 e.printStackTrace();  
  45.             } catch (IllegalArgumentException e) {  
  46.                 // TODO Auto-generated catch block  
  47.                 e.printStackTrace();  
  48.             } catch (InvocationTargetException e) {  
  49.                 // TODO Auto-generated catch block  
  50.                 e.printStackTrace();  
  51.             }  
  52.         }  
  53.           
  54.     }  
  55. }  

 对任务的暂停,删除,修改等操作

 

 

Java代码   收藏代码
  1. **  
  2.      * 获取所有计划中的任务列表  
  3.      *   
  4.      * @return  
  5.      * @throws SchedulerException  
  6.      */  
  7.     public List<ScheduleJob> getAllJob() throws SchedulerException {  
  8.         Scheduler scheduler = schedulerFactoryBean.getScheduler();  
  9.         GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();  
  10.         Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);  
  11.         List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();  
  12.         for (JobKey jobKey : jobKeys) {  
  13.             List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);  
  14.             for (Trigger trigger : triggers) {  
  15.                 ScheduleJob job = new ScheduleJob();  
  16.                 job.setJobName(jobKey.getName());  
  17.                 job.setJobGroup(jobKey.getGroup());  
  18.                 job.setDescription("触发器:" + trigger.getKey());  
  19.                 Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());  
  20.                 job.setJobStatus(triggerState.name());  
  21.                 if (trigger instanceof CronTrigger) {  
  22.                     CronTrigger cronTrigger = (CronTrigger) trigger;  
  23.                     String cronExpression = cronTrigger.getCronExpression();  
  24.                     job.setCronExpression(cronExpression);  
  25.                 }  
  26.                 jobList.add(job);  
  27.             }  
  28.         }  
  29.         return jobList;  
  30.     }  
  31.   
  32.     /** 
  33.      * 所有正在运行的job 
  34.      *  
  35.      * @return 
  36.      * @throws SchedulerException 
  37.      */  
  38.     public List<ScheduleJob> getRunningJob() throws SchedulerException {  
  39.         Scheduler scheduler = schedulerFactoryBean.getScheduler();  
  40.         List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();  
  41.         List<ScheduleJob> jobList = new ArrayList<ScheduleJob>(executingJobs.size());  
  42.         for (JobExecutionContext executingJob : executingJobs) {  
  43.             ScheduleJob job = new ScheduleJob();  
  44.             JobDetail jobDetail = executingJob.getJobDetail();  
  45.             JobKey jobKey = jobDetail.getKey();  
  46.             Trigger trigger = executingJob.getTrigger();  
  47.             job.setJobName(jobKey.getName());  
  48.             job.setJobGroup(jobKey.getGroup());  
  49.             job.setDescription("触发器:" + trigger.getKey());  
  50.             Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());  
  51.             job.setJobStatus(triggerState.name());  
  52.             if (trigger instanceof CronTrigger) {  
  53.                 CronTrigger cronTrigger = (CronTrigger) trigger;  
  54.                 String cronExpression = cronTrigger.getCronExpression();  
  55.                 job.setCronExpression(cronExpression);  
  56.             }  
  57.             jobList.add(job);  
  58.         }  
  59.         return jobList;  
  60.     }  
  61.   
  62.     /** 
  63.      * 暂停一个job 
  64.      *  
  65.      * @param scheduleJob 
  66.      * @throws SchedulerException 
  67.      */  
  68.     public void pauseJob(ScheduleJob scheduleJob) throws SchedulerException {  
  69.         Scheduler scheduler = schedulerFactoryBean.getScheduler();  
  70.         JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());  
  71.         scheduler.pauseJob(jobKey);  
  72.     }  
  73.   
  74.     /** 
  75.      * 恢复一个job 
  76.      *  
  77.      * @param scheduleJob 
  78.      * @throws SchedulerException 
  79.      */  
  80.     public void resumeJob(ScheduleJob scheduleJob) throws SchedulerException {  
  81.         Scheduler scheduler = schedulerFactoryBean.getScheduler();  
  82.         JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());  
  83.         scheduler.resumeJob(jobKey);  
  84.     }  
  85.   
  86.     /** 
  87.      * 删除一个job 
  88.      *  
  89.      * @param scheduleJob 
  90.      * @throws SchedulerException 
  91.      */  
  92.     public void deleteJob(ScheduleJob scheduleJob) throws SchedulerException {  
  93.         Scheduler scheduler = schedulerFactoryBean.getScheduler();  
  94.         JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());  
  95.         scheduler.deleteJob(jobKey);  
  96.   
  97.     }  
  98.   
  99.     /** 
  100.      * 立即执行job 
  101.      *  
  102.      * @param scheduleJob 
  103.      * @throws SchedulerException 
  104.      */  
  105.     public void runAJobNow(ScheduleJob scheduleJob) throws SchedulerException {  
  106.         Scheduler scheduler = schedulerFactoryBean.getScheduler();  
  107.         JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());  
  108.         scheduler.triggerJob(jobKey);  
  109.     }  
  110.   
  111.     /** 
  112.      * 更新job时间表达式 
  113.      *  
  114.      * @param scheduleJob 
  115.      * @throws SchedulerException 
  116.      */  
  117.     public void updateJobCron(ScheduleJob scheduleJob) throws SchedulerException {  
  118.         Scheduler scheduler = schedulerFactoryBean.getScheduler();  
  119.   
  120.         TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());  
  121.   
  122.         CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);  
  123.   
  124.         CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());  
  125.   
  126.         trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();  
  127.   
  128.         scheduler.rescheduleJob(triggerKey, trigger);  
  129.     }  

小提示

更新表达式,判断表达式是否正确可用一下代码

CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("xxxxx");

判定cron表达式是否正确可以直接用CronExpression.isValidExpression("");  返回类型是boolean型

抛出异常则表达式不正确


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值