发布时间:2018-12-03
技术:spring4.0.2+quartz2.2.1
概述
在最近工作中,由于涉及到定时任务特别多,而这些工作又是由下属去完成的,在生成环境中经常会出现业务逻辑错误,分析下来多数是定时任务运行问题,所以就希望把定时任务优化一下,主要实现2个方面 1.定时任务动态配置及持久化 2.可视化的管理界面,可以非常清晰的管理自己的所有定时任务 源码是我重新梳理后的(陆陆续续花了我好几天晚上),整个框架去除了多余的内容,仅保留quartz及springAop,能非常好的解决业务中的定时任务,而且还能所见即所得的知道目前有哪些任务在跑,对任务具体执行的情况进行日志分析;框架采用ssm搭建,结合自己工作中框架的结构问题做了优化,如果对这个单体架构感兴趣,底层可以在platform_parent中扩展,应用层可在cloud_parent中进行扩展
详细
一、准备工作
1.java环境搭建,具体参考包中的webapp/resources/doc/平台开发环境安装Guide_V1.0.docx文档
2.使用源码中的webapp/resources/doc/init.sql初始化表结构及数据
t_timetask 任务表
t_timetask_log 任务运行日志
3.数据库连接配置在cloud_parent中的pom.xml中,数据库名称ffxl_cloud,默认账号root,密码123456,同样可在pom.xml中修改
4.运行quartz项目,此处注意,使用的端口号需要与platform_parent下pom.xml中的quartz.job.url的一致,程序中用的是8080端口,具体使用哪个配置,请参考maven中profiles的使用
5.运行admin项目,注意,此处端口要与quartz不同,程序中用的是80端口,浏览器中输入http://localhost/admin 运行结果如图:
二、代码引入
1、文件引入顺序:lib_parent → platform_parent → cloud_parent
2、代码结构
三、程序实现
quartz项目部分代码
1.quartz项目启动时,初始化数据库中的定时任务
package com.ffxl.quartz.init;
import java.util.ArrayList;
import java.util.List;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import com.ffxl.cloud.model.STimetask;
import com.ffxl.cloud.model.STimetaskExample;
import com.ffxl.cloud.model.base.BaseSTimetaskExample.Criteria;
import com.ffxl.cloud.model.warpper.ScheduleJob;
import com.ffxl.cloud.service.STimetaskService;
import com.ffxl.quartz.task.util.QuartzJobFactory;
import com.ffxl.quartz.task.util.QuartzJobFactoryDisallowConcurrentExecution;
/**
* 根据上下文获取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) appCtx.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.提供job对应的操作服务
package com.ffxl.quartz.task;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONArray;
import org.apache.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONObject;
import com.ffxl.cloud.annotation.ControllerLogAnnotation;
import com.ffxl.cloud.model.STimetask;
import com.ffxl.cloud.model.warpper.ScheduleJob;
import com.ffxl.platform.util.JsonResult;
import com.ffxl.platform.util.StringUtil;
import com.ffxl.quartz.init.InitQuartzJob;
@Component
@RequestMapping(value = "/opt")
public class JobSerlvet {
public final Logger log = Logger.getLogger(this.getClass());
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
/**
* 获取所有计划中的任务列表
*
* @return
* @throws SchedulerException
* @thr