spring + quartz 之动态任务调度

1、任务调度:根据特定的时间规则自动执行相应的业务逻辑,quartz算是一种比较简单灵活的实现方式,但是不支持分布式.

2、maven依赖: 

1 <dependency>
2             <groupId>org.quartz-scheduler</groupId>
3             <artifactId>quartz</artifactId>
4             <version>2.2.1</version>
5 </dependency>
View Code

3、实现:

  1、创建任务常量类:

 1 package com.quartz;
 2 
 3 /**
 4  * Created by xiao on 2015/9/28.
 5  */
 6 public final class JobConstants {
 7 
 8 
 9     /**
10      * Job状态
11      */
12     public static class JobStatus{
13         /**
14          * 未处理
15          */
16         public static final String JOB_UNPROCESSED = "0";
17 
18         /**
19          * 执行成功
20          */
21         public static final String JOB_SUCCESSED = "1";
22 
23         /**
24          * 执行失败
25          */
26         public static final String JOB_FAILED = "-1";
27 
28         /**
29          * 过期
30          */
31         public static final String JOB_EXPIRED = "-2";
32     }
33 
34     /**
35      * 任务组
36      */
37     public static final class JobGruop{
38 
39         /**
40          * 默认的任务组
41          */
42         public static final String JOB_DEFAULT_GROUP_ = "job_default_group_id";
43 
44         /**
45          * 默认的任务组
46          */
47         public static final String JOB_DEFAULT_GROUP_NAME = "job_default_group_name";
48     }
49 
50     public static final class JobName{
51 
52         /**
53          * 默认的任务名
54          */
55         public static final String JOB_DEFAULT_ID = "job_default_id";
56 
57         /**
58          * 默认的任务名
59          */
60         public static final String JOB_DEFAULT_NAME = "job_default_name";
61     }
62 
63 }
View Code

  2、创建任务实体,封装任务参数: 

  1 package com.quartz;
  2 
  3 import java.util.Date;
  4 
  5 /**
  6  * 任务 实体
  7  * Created by xiao on 2015/9/28.
  8  */
  9 public final class Job implements java.io.Serializable {
 10 
 11     /**
 12      * 任务ID
 13      */
 14     private String jobId;
 15 
 16     /**
 17      * 任务名称
 18      */
 19     private String jobName;
 20 
 21     /**
 22      * 任务组id
 23      */
 24     private String jobGroupId;
 25     /**
 26      * 任务分组
 27      */
 28     private String jobGroup;
 29 
 30     /**
 31      * 创建时间
 32      */
 33     private Date createTime;
 34 
 35     /**
 36      * 更新时间
 37      */
 38     private Date updateTime;
 39 
 40     /**
 41      * 任务状态
 42      */
 43     private String jobStatus;
 44     /**
 45      * cron表达式
 46      */
 47     private String cronExpression;
 48 
 49     /**
 50      * 简单时间表达式
 51      */
 52     private Date simpleExpression;
 53 
 54     /**
 55      * 任务执行时调用哪个类的方法 包名+类名
 56      */
 57     private String jobClassName;
 58 
 59     /**
 60      * 任务调用的方法名
 61      */
 62     private String jobMethodName;
 63 
 64     /**
 65      * 任务是否有状态(即并发执行同一个任务)
 66      */
 67     private boolean isConcurrent = true;
 68 
 69     /**
 70      * 描述
 71      */
 72     private String description;
 73 
 74 
 75     public String getJobId() {
 76         return jobId;
 77     }
 78 
 79     public void setJobId(String jobId) {
 80         this.jobId = jobId;
 81     }
 82 
 83     public String getJobName() {
 84         return jobName;
 85     }
 86 
 87     public void setJobName(String jobName) {
 88         this.jobName = jobName;
 89     }
 90 
 91     public String getJobGroupId() {
 92         return jobGroupId;
 93     }
 94 
 95     public void setJobGroupId(String jobGroupId) {
 96         this.jobGroupId = jobGroupId;
 97     }
 98 
 99     public String getJobGroup() {
100         return jobGroup;
101     }
102 
103     public void setJobGroup(String jobGroup) {
104         this.jobGroup = jobGroup;
105     }
106 
107     public Date getCreateTime() {
108         return createTime;
109     }
110 
111     public void setCreateTime(Date createTime) {
112         this.createTime = createTime;
113     }
114 
115     public Date getUpdateTime() {
116         return updateTime;
117     }
118 
119     public void setUpdateTime(Date updateTime) {
120         this.updateTime = updateTime;
121     }
122 
123     public String getJobStatus() {
124         return jobStatus;
125     }
126 
127     public void setJobStatus(String jobStatus) {
128         this.jobStatus = jobStatus;
129     }
130 
131     public String getCronExpression() {
132         return cronExpression;
133     }
134 
135     public void setCronExpression(String cronExpression) {
136         this.cronExpression = cronExpression;
137     }
138 
139     public Date getSimpleExpression() {
140         return simpleExpression;
141     }
142 
143     public void setSimpleExpression(Date simpleExpression) {
144         this.simpleExpression = simpleExpression;
145     }
146 
147     public String getJobClassName() {
148         return jobClassName;
149     }
150 
151     public void setJobClassName(String jobClassName) {
152         this.jobClassName = jobClassName;
153     }
154 
155     public String getJobMethodName() {
156         return jobMethodName;
157     }
158 
159     public void setJobMethodName(String jobMethodName) {
160         this.jobMethodName = jobMethodName;
161     }
162 
163     public boolean isConcurrent() {
164         return isConcurrent;
165     }
166 
167     public void setConcurrent(boolean concurrent) {
168         isConcurrent = concurrent;
169     }
170 
171     public String getDescription() {
172         return description;
173     }
174 
175     public void setDescription(String description) {
176         this.description = description;
177     }
178 }
View Code

  3、创建任务管理器,实现了任务动态的增、删、更新、暂停等操作   

  1 package com.quartz;
  2 
  3 import com.quartz.job.DefaultJobFactory;
  4 import com.quartz.job.DisallowConcurrentJobFactory;
  5 import org.quartz.*;
  6 import org.quartz.impl.StdScheduler;
  7 import org.quartz.impl.matchers.GroupMatcher;
  8 import util.FastJsonUtil;
  9 import util.StringUtil;
 10 
 11 import java.util.ArrayList;
 12 import java.util.List;
 13 import java.util.Set;
 14 
 15 /**
 16  * 任务调度管理器, 实现任务的动态操作
 17  * Created by xiao on 2015/9/28.
 18  */
 19 public class JobManager {
 20 
 21     //为调度管理器注入工厂bean
 22     private StdScheduler scheduler;
 23 
 24     //调度名称
 25     private static final String SCHEDULER_NAME = "scheduler";
 26 
 27     public StdScheduler getScheduler() {
 28         return scheduler;
 29     }
 30 
 31     public void setScheduler(StdScheduler scheduler) {
 32         this.scheduler = scheduler;
 33     }
 34 
 35     /**
 36      * 添加任务
 37      * @param job
 38      * @throws SchedulerException
 39      */
 40     public void addJob(Job job) throws SchedulerException, ClassNotFoundException {
 41         if (job == null || StringUtil.isEmptyString(job.getJobId())) return;
 42         if(StringUtil.isEmptyString(job.getCronExpression())
 43                 && null == job.getSimpleExpression()) return;
 44         if (StringUtil.isEmptyString(job.getJobClassName())) return;
 45         if(StringUtil.isEmptyString(job.getJobName()))
 46             job.setJobName(JobConstants.JobName.JOB_DEFAULT_NAME);
 47         if(null == job.getSimpleExpression()) {
 48             addCronJob(job);
 49         }else{
 50             addSimpleJob(job);
 51         }
 52     }
 53 
 54     /**
 55      * 添加 cron 表达式任务
 56      * @param job
 57      * @throws SchedulerException
 58      * @throws ClassNotFoundException
 59      */
 60     private void addCronJob(Job job) throws SchedulerException, ClassNotFoundException {
 61         //根据任务id和任务组Id创建触发器key
 62         TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(), job.getJobGroup());
 63         //获取触发器对象
 64         CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
 65         // 不存在,创建一个
 66         if (null == trigger) {
 67             JobDetail jobDetail = JobBuilder.newJob(job.isConcurrent() ? DefaultJobFactory.class : DisallowConcurrentJobFactory.class)
 68                     .withIdentity(job.getJobId(), job.getJobGroup()).build();
 69             jobDetail.getJobDataMap().put(SCHEDULER_NAME, FastJsonUtil.objToJson(job));
 70             trigger = TriggerBuilder.newTrigger()
 71                     .withIdentity(triggerKey)
 72                     .withSchedule(CronScheduleBuilder.cronSchedule(
 73                             job.getCronExpression())).build();
 74             scheduler.scheduleJob(jobDetail, trigger);
 75         } else {
 76             updateJobCron(job);
 77         }
 78     }
 79 
 80     /**
 81      * 添加 简单时间 表达式任务
 82      * @param job
 83      * @throws SchedulerException
 84      * @throws ClassNotFoundException
 85      */
 86     private void addSimpleJob(Job job) throws SchedulerException {
 87         //根据任务id和任务组Id创建触发器key
 88         TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(), job.getJobGroup());
 89         //获取触发器对象
 90         SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
 91         // 不存在,创建一个
 92         if (null == trigger) {
 93             JobDetail jobDetail = JobBuilder.newJob(job.isConcurrent() ? DefaultJobFactory.class : DisallowConcurrentJobFactory.class)
 94                     .withIdentity(job.getJobId(), job.getJobGroup()).build();
 95             jobDetail.getJobDataMap().put(SCHEDULER_NAME, FastJsonUtil.objToJson(job));
 96             trigger = TriggerBuilder.newTrigger()
 97                     .withIdentity(triggerKey)
 98                     .withSchedule(SimpleScheduleBuilder.simpleSchedule())
 99                     .startAt(job.getSimpleExpression()).build();
100             scheduler.scheduleJob(jobDetail, trigger);
101         } else {
102             updateJobSimple(job);
103         }
104     }
105 
106     /**
107      * 更新job时间表达式
108      *
109      * @param job
110      * @throws SchedulerException
111      */
112     public void updateJobCron(Job job) throws SchedulerException {
113         TriggerKey triggerKey = TriggerKey.triggerKey(
114                 job.getJobId(), job.getJobGroup());
115         CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
116         trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
117                 .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())).build();
118         scheduler.rescheduleJob(triggerKey, trigger);
119     }
120 
121     /**
122      * 更新job时间表达式
123      *
124      * @param job
125      * @throws SchedulerException
126      */
127     public void updateJobSimple(Job job) throws SchedulerException {
128         TriggerKey triggerKey = TriggerKey.triggerKey(
129                 job.getJobId(), job.getJobGroup());
130         SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
131         trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
132                 .withSchedule(SimpleScheduleBuilder.simpleSchedule())
133                 .startAt(job.getSimpleExpression()).build();
134         scheduler.rescheduleJob(triggerKey, trigger);
135     }
136 
137     /** 获取所有计划中的任务列表
138      * @return
139      * @throws SchedulerException
140      **/
141     public List<Job> getAllJob() throws SchedulerException {
142         GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
143         Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
144         List<Job> jobList = new ArrayList<>();
145         for (JobKey jobKey : jobKeys) {
146             List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
147             for (Trigger trigger : triggers) {
148                 Job job = new Job();
149                 job.setJobId(jobKey.getName());
150                 job.setJobGroup(jobKey.getGroup());
151                 Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
152                 job.setJobStatus(triggerState.name());
153                 if (trigger instanceof CronTrigger) {
154                     CronTrigger cronTrigger = (CronTrigger) trigger;
155                     String cronExpression = cronTrigger.getCronExpression();
156                     job.setCronExpression(cronExpression);
157                 }
158                 jobList.add(job);
159             }
160         }
161         return jobList;
162     }
163 
164     /**
165      * 所有正在运行的job
166      *
167      * @return
168      * @throws SchedulerException
169      */
170     public List<Job> getRunningJob() throws SchedulerException {
171         List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
172         List<Job> jobList = new ArrayList<>(executingJobs.size());
173         for (JobExecutionContext executingJob : executingJobs) {
174             Job job = new Job();
175             JobDetail jobDetail = executingJob.getJobDetail();
176             JobKey jobKey = jobDetail.getKey();
177             Trigger trigger = executingJob.getTrigger();
178             job.setJobName(jobKey.getName());
179             job.setJobGroup(jobKey.getGroup());
180             Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
181             job.setJobStatus(triggerState.name());
182             if (trigger instanceof CronTrigger) {
183                 CronTrigger cronTrigger = (CronTrigger) trigger;
184                 String cronExpression = cronTrigger.getCronExpression();
185                 job.setCronExpression(cronExpression);
186             }
187             jobList.add(job);
188         }
189         return jobList;
190     }
191 
192     /**
193      * 暂停一个job
194      *
195      * @param scheduleJob
196      * @throws SchedulerException
197      */
198     public void pauseJob(Job scheduleJob) throws SchedulerException {
199         JobKey jobKey = JobKey.jobKey(scheduleJob.getJobId(), scheduleJob.getJobGroup());
200         scheduler.pauseJob(jobKey);
201     }
202 
203     /**
204      * 恢复一个job
205      *
206      * @param job
207      * @throws SchedulerException
208      */
209     public void resumeJob(Job job) throws SchedulerException {
210         JobKey jobKey = JobKey.jobKey(job.getJobId(), job.getJobGroup());
211         scheduler.resumeJob(jobKey);
212     }
213 
214     /**
215      * 删除一个job
216      *
217      * @param scheduleJob
218      * @throws SchedulerException
219      */
220     public void deleteJob(Job scheduleJob) throws SchedulerException {
221         JobKey jobKey = JobKey.jobKey(scheduleJob.getJobId(), scheduleJob.getJobGroup());
222         scheduler.deleteJob(jobKey);
223 
224     }
225 
226     /**
227      * 立即执行job
228      *
229      * @param job
230      * @throws SchedulerException
231      */
232     public void triggerJob(Job job) throws SchedulerException {
233         JobKey jobKey = JobKey.jobKey(job.getJobId(), job.getJobGroup());
234         scheduler.triggerJob(jobKey);
235     }
236 
237 
238 }
View Code

  4、创建任务执行类,这个类需要实现 org.quarzt.Job 接口, Job接口有一个excute(JobExecutionContext context) 方法, 调度被处罚以后会自动执行, 再次我们实现这个方法, 通过反射来转发到我们创建任务时指定执行的方法, 代码如下:

 1 package com.quartz.job;
 2 
 3 import com.quartz.Job;
 4 import org.quartz.JobExecutionContext;
 5 import org.quartz.JobExecutionException;
 6 import util.FastJsonUtil;
 7 import util.StringUtil;
 8 
 9 /**
10  * Created by xiao on 2015/9/29.
11  */
12 public class DefaultJobFactory extends  AbstractJobFactory implements org.quartz.Job {
13 
14     public void execute(JobExecutionContext context) throws JobExecutionException {
15         String scheduleJob = (String) context.getMergedJobDataMap().get("scheduler");
16         if(!StringUtil.isEmptyString(scheduleJob)){
17             Job job = FastJsonUtil.jsonToObj(scheduleJob, Job.class);
18             invoke(job);
19         }
20 
21     }
22 }
View Code
 1 package com.quartz.job;
 2 
 3 import org.quartz.DisallowConcurrentExecution;
 4 import org.quartz.Job;
 5 import org.quartz.JobExecutionContext;
 6 import org.quartz.JobExecutionException;
 7 import util.FastJsonUtil;
 8 import util.StringUtil;
 9 
10 /**
11  * Created by xiao on 2015/9/29.
12  */
13 @DisallowConcurrentExecution
14 public class DisallowConcurrentJobFactory extends  AbstractJobFactory implements Job {
15 
16     public void execute(JobExecutionContext context) throws JobExecutionException {
17 
18         String scheduleJob = (String) context.getMergedJobDataMap().get("scheduler");
19         if(!StringUtil.isEmptyString(scheduleJob)){
20             com.quartz.Job job = FastJsonUtil.jsonToObj(scheduleJob, com.quartz.Job.class);
21             invoke(job);
22         }
23     }
24 }
View Code
 1 package com.quartz.job;
 2 
 3 import com.quartz.Job;
 4 import util.SpringBeanUtil;
 5 import util.StringUtil;
 6 
 7 import java.lang.reflect.InvocationTargetException;
 8 import java.lang.reflect.Method;
 9 
10 /**
11  * Created by xiao on 2016/4/29.
12  */
13 public class AbstractJobFactory {
14 
15     public void invoke(Job job){
16         if(!StringUtil.isEmptyString(job.getJobClassName())){
17             try {
18                 Class<?> clazz = Class.forName(job.getJobClassName());
19                 //从spring容器获取bean,否则无法注入
20                 Object obj = SpringBeanUtil.getBeanByType(clazz);
21                 //反射方法
22                 Method method = obj.getClass().getDeclaredMethod(job.getJobMethodName());
23                 method.invoke(obj, job);
24             } catch (ClassNotFoundException e) {
25                 e.printStackTrace();
26             } catch (NoSuchMethodException e) {
27                 e.printStackTrace();
28             } catch (IllegalAccessException e) {
29                 e.printStackTrace();
30             } catch (InvocationTargetException e) {
31                 e.printStackTrace();
32             }
33         }
34     }
35 }
View Code

  获取bean 工具类:

 1 package util;
 2 
 3 import org.springframework.web.context.ContextLoader;
 4 import org.springframework.web.context.WebApplicationContext;
 5 
 6 public final class SpringBeanUtil {
 7 
 8     //获取web容器上下文
 9     private static WebApplicationContext wac = ContextLoader
10             .getCurrentWebApplicationContext();
11 
12     /**
13      * 违背了 Spring 依赖注入思想
14      *
15      * @param beanId
16      * @return
17      */
18     public static Object getBeanByName(String beanId) throws Exception {
19         if (StringUtil.isEmptyString(beanId)) {
20             throw new Exception("beanId is null");
21         }
22         return wac.getBean(beanId);
23 
24     }
25 
26     /**
27      *  违背spring的ioc解耦思想。
28      */
29     public static  <T> T getBeanByType(Class clazz) {
30         if (clazz == null) {
31             return null;
32         }
33         return (T) wac.getBean(clazz);
34     }
35 }
View Code

  FastJson 序列化工具类, FastJson是阿里开源的号称最快的序列化工具

 1 package util;
 2 
 3 import com.alibaba.fastjson.JSON;
 4 import com.alibaba.fastjson.serializer.SerializerFeature;
 5 
 6 /**
 7  * FastJson 序列化工具
 8  *
 9  * @author xiao
10  *
11  */
12 public final class FastJsonUtil {
13 
14     /**
15      * 序列化参数
16      */
17     private static final SerializerFeature[] features = {
18             SerializerFeature.WriteMapNullValue,
19             SerializerFeature.WriteNullBooleanAsFalse,
20             SerializerFeature.WriteNullStringAsEmpty,
21             SerializerFeature.WriteNullListAsEmpty,
22             SerializerFeature.WriteNullNumberAsZero };
23 
24     /**
25      * 对象转换成json 支持list,map,array
26      *
27      * @param obj
28      * @return
29      */
30     public static String objToJson(Object obj) {
31         return JSON.toJSONString(obj, features);
32     }
33 
34 
35     /**
36      * json 转换成对象
37      *
38      * @param json
39      * @param clazz
40      * @return
41      */
42     public static <T> T jsonToObj(String json, Class<?> clazz) {
43         return (T) JSON.parseObject(json, clazz);
44     }
45 }
View Code

  5、最后一步, 在spring中集成,配置如下:

1     <!-- 任务管理器 -->
2     <bean class="com.quartz.JobManager">
3         <property name="scheduler">
4         <!-- 将触发器注入任务工程 -->
5             <bean id="scheduler" lazy-init="false" scope="singleton"
6                   class="org.springframework.scheduling.quartz.SchedulerFactoryBean"/>
7         </property>
8     </bean>
View Code

 

posted @ 2016-04-29 18:30  沐风^_^  阅读(2839)  评论(5编辑  收藏  举报