最近公司在分发系统整合,原本选型阶段选择xxl-job国内开源框架,了解后,在这个框架,实际用不到其中的十分之一。利用闲暇时间,自己写了一个定时任务Demo
相关接口描述
Controller
/**
* 定时任务
* @author xiaozhi 2018年4月27日 上午11:30:29
*/
@RestController
@RequestMapping("quartz")
@Api(value="/quartz", description="定时任务接口", produces="application/json")
public class JobController {
@Autowired
private JobService jobService;
@RequestMapping(method = RequestMethod.POST, value = "/add")
@ApiOperation(value = "新增任务", httpMethod = "POST", response = ReturnMsg.class, notes = "新增任务", position = 2)
public ReturnMsg add(@RequestBody Job job) {
return jobService.addJob(job);
}
@RequestMapping(method = RequestMethod.POST, value = "/edit")
@ApiOperation(value = "编辑任务", httpMethod = "POST", response = ReturnMsg.class, notes = "编辑任务", position = 3)
public ReturnMsg edit(@RequestBody Job job){
return jobService.editJob(job);
}
@RequestMapping(method = RequestMethod.POST, value = "/del")
@ApiOperation(value = "删除任务", httpMethod = "POST", response = ReturnMsg.class, notes = "删除任务", position = 4)
public ReturnMsg del(@RequestParam("jobId") Long jobId){
return jobService.delJob(jobId);
}
@RequestMapping(method = RequestMethod.POST, value = "/list")
@ApiOperation(value = "任务列表", httpMethod = "POST", response = ReturnMsg.class, notes = "任务列表", position = 1)
public ReturnMsg list(){
return jobService.list();
}
}
Service
/**
* 定时任务ServiceImpl
*
* @author xiaozhi 2018年4月27日 下午1:46:35
*/
@Service("jobServiceImpl")
public class JobServiceImpl extends AbstractService implements JobService {
@Autowired
private Scheduler scheduler;
@PostConstruct
public void initJob() {
try {
List<Job> jobList = this.baseDAO.selectListByMappingId("selectJobAll");
for (Job job : jobList) {
CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, job.getJobId());
// 如果不存在,则创建
if (cronTrigger == null) {
ScheduleUtils.createScheduleJob(scheduler, job);
} else {
ScheduleUtils.updateScheduleJob(scheduler, job);
}
}
} catch (Exception e) {
logger.info("系统启动初始化,加载所有定时任务 Error Msg = " + e.getMessage(), e);
}
}
/**
* 添加/更新定时任务 @author xiaozhi 2018年4月27日 下午6:33:32 @param job 定时任务参数集 @return
* ReturnMsg @throws
*/
@Override
public ReturnMsg addJob(Job job) {
try {
Long jobId = job.getJobId();
// 若任务ID存在,则更新操作,反之,新增操作
if (jobId != null) {
int check = this.baseDAO.update(job, "updateJobCron");
if (check > 0) {
ScheduleUtils.updateScheduleJob(scheduler, job);
return new ReturnMsg(ReturnMsg.SUCCESS, "任务已存在, 更新成功");
}
} else {
job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
int check = this.baseDAO.insert(job, "insertJob");
if (check > 0) {
ScheduleUtils.createScheduleJob(scheduler, job);
return new ReturnMsg(ReturnMsg.SUCCESS, "新增成功");
}
}
} catch (Exception e) {
logger.info("添加/更新定时任务 Error Msg = " + e.getMessage(), e);
}
return new ReturnMsg(ReturnMsg.FAIL, "操作成功");
}
/**
* 删除定时任务 @author xiaozhi 2018年4月27日 下午6:35:05 @param jobId 任务ID @return
* ReturnMsg @throws
*/
@Override
public ReturnMsg delJob(Long jobId) {
try {
// 查询是否存在
Job job = this.baseDAO.selectOne(jobId, "selectJobById");
if (job != null && job.getJobId() > 0) {
int check = this.baseDAO.delete(jobId, "deleteJobById");
if (check > 0) {
ScheduleUtils.deleteScheduleJob(scheduler, jobId);
return new ReturnMsg(ReturnMsg.SUCCESS, "删除成功");
}
}
} catch (Exception e) {
logger.info("删除定时任务 Error Msg = " + e.getMessage(), e);
}
return new ReturnMsg(ReturnMsg.FAIL, "删除失败");
}
/**
* 编辑定时任务 @author xiaozhi 2018年4月27日 下午6:35:57 @param job 定时任务参数集 @return
* ReturnMsg @throws
*/
@Override
public ReturnMsg editJob(Job job) {
try {
if (job != null && job.getStatus() == 0) {
job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
int check = this.baseDAO.update(job, "updateJob");
if (check > 0) {
ScheduleUtils.resumeJob(scheduler, job.getJobId());
}
return new ReturnMsg(ReturnMsg.SUCCESS, "编辑成功!");
} else if (job != null && job.getStatus() == 1) {
job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
int check = this.baseDAO.update(job, "updateJob");
if (check > 0) {
ScheduleUtils.pauseJob(scheduler, job.getJobId());
}
return new ReturnMsg(ReturnMsg.SUCCESS, "编辑成功!");
}
} catch (Exception e) {
logger.info("编辑定时任务 Error Msg = " + e.getMessage(), e);
}
return new ReturnMsg(ReturnMsg.FAIL, "编辑失败!");
}
/**
* 查询定时任务列表 @author xiaozhi 2018年4月27日 下午7:12:00 @return ReturnMsg @throws
*/
@Override
public ReturnMsg list() {
try {
List<Job> jobList = this.baseDAO.selectListByMappingId("selectJobList");
TableDataInfo pageData = PageUtils.pageDB(jobList);
return new ReturnMsg(ReturnMsg.SUCCESS, "查询成功", pageData);
} catch (Exception e) {
logger.info("查询定时任务列表 Error Msg = " + e.getMessage(), e);
}
return new ReturnMsg(ReturnMsg.FAIL, "查询失败");
}
}
定时任务工具类
/**
* 定时任务工具类
*
* @author xiaozhi 2018年4月28日 上午9:18:56
*/
public class ScheduleUtils {
// 初始化log
private static final Logger log = LoggerFactory.getLogger(ScheduleUtils.class);
private final static String JOB_NAME = "TASK_";
/**
* 获取触发器key
*/
public static TriggerKey getTriggerKey(Long jobId) {
return TriggerKey.triggerKey(JOB_NAME + jobId);
}
/**
* 获取jobKey
*/
public static JobKey getJobKey(Long jobId) {
return JobKey.jobKey(JOB_NAME + jobId);
}
/**
* 获取表达式触发器
*/
public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) {
try {
return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
} catch (SchedulerException e) {
log.error(e.getMessage());
}
return null;
}
/**
* 创建定时任务
*/
public static void createScheduleJob(Scheduler scheduler, Job job) {
try {
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(job.getJobId())).build();
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(job.getJobId()))
.withSchedule(scheduleBuilder).build();
// 放入参数,运行时的方法可以获取
jobDetail.getJobDataMap().put(ScheduleConstants.JOB_PARAM_KEY, job);
scheduler.scheduleJob(jobDetail, trigger);
// 暂停任务
if (job.getStatus() == ScheduleConstants.Status.PAUSE.getValue()) {
pauseJob(scheduler, job.getJobId());
}
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 更新定时任务
*/
public static void updateScheduleJob(Scheduler scheduler, Job job) {
try {
TriggerKey triggerKey = getTriggerKey(job.getJobId());
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
CronTrigger trigger = getCronTrigger(scheduler, job.getJobId());
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 参数
trigger.getJobDataMap().put(ScheduleConstants.JOB_PARAM_KEY, job);
scheduler.rescheduleJob(triggerKey, trigger);
// 暂停任务
if (job.getStatus() == ScheduleConstants.Status.PAUSE.getValue()) {
pauseJob(scheduler, job.getJobId());
}
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 立即执行任务
*/
public static void run(Scheduler scheduler, Job job) {
try {
// 参数
JobDataMap dataMap = new JobDataMap();
dataMap.put(ScheduleConstants.JOB_PARAM_KEY, job);
scheduler.triggerJob(getJobKey(job.getJobId()), dataMap);
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 暂停任务
*/
public static void pauseJob(Scheduler scheduler, Long jobId) {
try {
scheduler.pauseJob(getJobKey(jobId));
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 恢复任务
*/
public static void resumeJob(Scheduler scheduler, Long jobId) {
try {
scheduler.resumeJob(getJobKey(jobId));
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
/**
* 删除定时任务
*/
public static void deleteScheduleJob(Scheduler scheduler, Long jobId) {
try {
scheduler.deleteJob(getJobKey(jobId));
} catch (SchedulerException e) {
log.error(e.getMessage());
}
}
}
系统启动的时候,首先查询数据库中所有定时任务,加载至 scheduler 中。
持久层,我使用BaseDao工具类操作
定时任务执行,采用 重载QuartzJobBean-executeInternal,在执行定时任务同时也会把运行日志写入至数据库中。
public class ScheduleJob extends QuartzJobBean {
private static final Logger log = LoggerFactory.getLogger(ScheduleJob.class);
private ExecutorService service = Executors.newSingleThreadExecutor();
/**
* 重载QuartzJobBean-executeInternal
*/
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
Job job = (Job) context.getMergedJobDataMap().get(ScheduleConstants.JOB_PARAM_KEY);
JobLogService jobLogService = (JobLogService) SpringUtils.getBean(JobLogService.class);
// 定时任务日志数据入库
JobLog jobLog = new JobLog();
jobLog.setJobName(job.getJobName());
jobLog.setJobGroup(job.getJobGroup());
jobLog.setMethodName(job.getMethodName());
jobLog.setParams(job.getParams());
jobLog.setCreateTime(new Date());
long startTime = System.currentTimeMillis();
try {
// 执行任务
log.info("任务开始执行 - 名称:{} 方法:{}", job.getJobName(), job.getMethodName());
ScheduleRunnable task = new ScheduleRunnable(job.getJobName(), job.getMethodName(), job.getParams());
Future<?> future = service.submit(task);
future.get();
long times = System.currentTimeMillis() - startTime;
// 任务状态 0:成功 1:失败
jobLog.setIsException(0);
jobLog.setJobMessage(job.getJobName() + " 总共耗时:" + times + "毫秒");
log.info("任务执行结束 - 名称:{} 耗时:{} 毫秒", job.getJobName(), times);
} catch (Exception e) {
log.info("任务执行失败 - 名称:{} 方法:{}", job.getJobName(), job.getMethodName());
log.error("任务执行异常 - :", e);
log.info("Error Msg = "+e.getMessage(), e);
long times = System.currentTimeMillis() - startTime;
jobLog.setJobMessage(job.getJobName() + " 总共耗时:" + times + "毫秒");
// 任务状态 0:成功 1:失败
jobLog.setIsException(1);
jobLog.setExceptionInfo(e.toString());
} finally {
// 添加定时任务运行日志
jobLogService.addJobLog(jobLog);
}
}
}
下载地址:
https://download.csdn.net/download/everyday_hzg/10387684
欢迎吐槽,共同进步。