在最近工作中,由于涉及到定时任务特别多,而这些工作又是由下属去完成的,在生成环境中经常会出现业务逻辑错误,分析下来多数是定时任务运行问题,所以就希望把定时任务优化一下,主要实现2个方面
1.定时任务动态配置及持久化
2.可视化的管理界面,可以非常清晰的管理自己的所有定时任务
首先,我们先来看第一个目标
一、版本说明
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)
此示例所选版本:4.0.2.RELEASE,quartz版本2.2.1
二、pom中引用相关包
三、数据结构
t_timetask 任务表
t_timetask_log 任务运行日志
接下来把代码抛出来
1.项目启动时,初始化数据库中的定时任务
- /
- 根据上下文获取spring类
- @author
- /
- public class InitQuartzJob implements ApplicationContextAware {
- private static final Logger logger = LoggerFactory.getLogger(InitQuartzJob.class);
- private static ApplicationContext appCtx;
- public static SchedulerFactoryBean schedulerFactoryBean = null;
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- if (this.appCtx == null) {
- this.appCtx = applicationContext;
- }
- }
- public static void init() {
- schedulerFactoryBean = (SchedulerFactoryBean) appCtx.getBean(SchedulerFactoryBean.class);
- Scheduler scheduler = schedulerFactoryBean.getScheduler();
- try {
- logger.info(scheduler.getSchedulerName());
- } catch (SchedulerException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- // 这里从数据库中获取任务信息数据
- STimetaskService sTimetaskService = (STimetaskService) ApplicationContextUtils.getBean(STimetaskService.class);
- STimetaskExample example = new STimetaskExample();
- Criteria c = example.createCriteria();
- c.andJobStatusEqualTo("1"); // 已发布的定时任务
- List<STimetask> list = sTimetaskService.selectByExample(example);
- List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
- for (STimetask sTimetask : list) {
- ScheduleJob job1 = new ScheduleJob();
- job1.setJobId(sTimetask.getId());
- job1.setJobGroup(sTimetask.getGroupName()); // 任务组
- job1.setJobName(sTimetask.getName());// 任务名称
- job1.setJobStatus(sTimetask.getJobStatus()); // 任务发布状态
- job1.setIsConcurrent(sTimetask.getConcurrent() ? "1" : "0"); // 运行状态
- job1.setCronExpression(sTimetask.getCron());
- job1.setBeanClass(sTimetask.getBeanName());// 一个以所给名字注册的bean的实例
- job1.setMethodName(sTimetask.getMethodName());
- job1.setJobData(sTimetask.getJobData()); // 参数
- jobList.add(job1);
- }
- for (ScheduleJob job : jobList) {
- try {
- addJob(job);
- } catch (SchedulerException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- /
- 添加任务
- @param scheduleJob
- @throws SchedulerException
- /
- public static void addJob(ScheduleJob job) throws SchedulerException {
- if (job == null || !ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) {
- return;
- }
- Scheduler scheduler = schedulerFactoryBean.getScheduler();
- logger.debug(scheduler + "...........................................add");
- TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
- CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
- // 不存在,创建一个
- if (null == trigger) {
- Class clazz = ScheduleJob.CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class
- : QuartzJobFactoryDisallowConcurrentExecution.class;
- JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).usingJobData("data", job.getJobData()).build();
- jobDetail.getJobDataMap().put("scheduleJob", job);
- CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
- trigger = TriggerBuilder.newTrigger().withDescription(job.getJobId().toString()).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).usingJobData("data", job.getJobData()).withSchedule(scheduleBuilder).build();
- // 按新的trigger重新设置job执行
- scheduler.rescheduleJob(triggerKey, trigger);
- }
- }
- }
- 2.1工具类
- package com.ffxl.cloud.quartz;
- import org.apache.log4j.Logger;
- import org.quartz.Job;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
- /**
- @Description: 计划任务执行处 无状态
- @author wison
- @date 2017年11月11日 下午5:05:47
- /
- public class QuartzJobFactory implements Job {
- public final Logger log = Logger.getLogger(this.getClass());
- public void execute(JobExecutionContext context) throws JobExecutionException {
- ScheduleJob scheduleJob = (ScheduleJob) context.getMergedJobDataMap().get("scheduleJob");
- TaskUtils.invokMethod(scheduleJob);
- }
- }
2.2
- /
- @Description: 若一个方法一次执行不完下次轮转时则等待改方法执行完后才执行下一次操作
- @author wison
- @date 2017年11月11日 下午5:05:47
- */
- @DisallowConcurrentExecution
- public class QuartzJobFactoryDisallowConcurrentExecution implements Job {
- public final Logger log = Logger.getLogger(this.getClass());
- public void execute(JobExecutionContext context) throws JobExecutionException {
- ScheduleJob scheduleJob = (ScheduleJob) context.getMergedJobDataMap().get("scheduleJob");
- TaskUtils.invokMethod(scheduleJob);
- }
- }
2.3
2.4
2.5
四、配置
- <!-- 初始化springUtils -->
- <bean id="springUtils" class="com.ffxl.cloud.quartz.SpringUtils" />
- <!-- 初始化Scheduler -->
- <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" />
- <!-- 初始化job -->
- <bean id="initQuartzJob" class="com.ffxl.quartz.init.InitQuartzJob" init-method="init" lazy-init="false" />