@TOCSSM项目动态实现定时任务管理
Quartz
在这里我的开发环境是idea2019+jdk1.8+mysql5.7
最近项目中的定时任务多了,就想了想,应该有管理功能来实现定时和发布
- layui ,展示页面我用的是layui,很方便的;
- 后端使用的是Spring,Springmvc,Mybaties,就是 SSM 框架;
- 在这里说明一下,如果再执行代码方法里面调用service方法,有一个点很重要 不要创建构造函数 ,不然的话,定时任务启动会报错org.quartz.SchedulerException: Problem instantiating class ‘guilinsoft.ddsx.quartz.MCron’ [See nested exception: java.lang.IllegalAccessException: Class org.quartz.simpl.SimpleJobFactory can not access a member of class guilinsoft.ddsx.quartz.MCron with modifiers “”]
Caused by: java.lang.IllegalAccessException: Class org.quartz.simpl.SimpleJobFactory can not access a member of class guilinsoft.ddsx.quartz.MCron with modifiers “”;
4. 调用service接口方法需要Spring的工具类,用来获得配置文件中的bean
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBeanByClass(Class<T> c){
return context.getBean(c);
}
public static Object getBeanByName(String name){
return context.getBean(name);
}
}
[^1]: [mermaid语法说明](https://mermaidjs.github.io/)
Quartz pom.xml中
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.0</version>
</dependency>
Quartz Spring-mvc.xml中
<bean id="instantiationTracingBeanPostProcessor" init-method="autoLoadTask" class="com.mlwy.controller.quartz.InstantiationTracingBeanPostProcessor">
</bean>
下面展示一些 内联代码片
。
public class InstantiationTracingBeanPostProcessor {
private static final Logger log = Logger.getLogger(InstantiationTracingBeanPostProcessor.class);
// 自己的定时任务管理Service,可自定义(需要改成自己的)
QuartzService quartzService = SpringContextUtils.getBeanByClass(QuartzService.class);
public QuartzService getQuartzService() {
return quartzService;
}
public void setQuartzService(QuartzService quartzService) {
this.quartzService = quartzService;
}
InstantiationTracingBeanPostProcessor(){}
InstantiationTracingBeanPostProcessor(QuartzService quartzService){
this.quartzService = quartzService;
}
/* spring加载完就执行该方法:init-method="autoLoadTask" */
public void autoLoadTask() {
//获取到所有需要启动的quartz集合
log.info("【系统启动】所有定时任务开启...");
List<QuartzVO> quartzList = quartzService.listQuartzByOn();
if(Util.isEmpty(quartzList) == true){
return;
}
for(int i=0;i<quartzList.size();i++){
Class clazz = null;
try {
clazz = Class.forName(quartzList.get(i).getClassname());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
QuartzManager.addJob(quartzList.get(i).getJobname(), clazz, quartzList.get(i).getTriggercron());
}
}
}
Quartz mysql5.7 sql
DROP TABLE IF EXISTS bj_mlwy_quartz;
CREATE TABLE `bj_mlwy_quartz` (
`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键(自增)',
`jobgroup` VARCHAR(120)DEFAULT NULL COMMENT '任务组',
`triggergroup` VARCHAR(120)DEFAULT NULL COMMENT '触发器组',
`jobname` VARCHAR(60)DEFAULT NULL COMMENT '任务名',
`triggername` VARCHAR(60)DEFAULT NULL COMMENT '触发器名',
`classname` VARCHAR(255)DEFAULT NULL COMMENT '执行代码的类名',
`enablestatus` INT(1) DEFAULT '1' COMMENT '是否禁用:0禁用;1启用',
`triggercron` VARCHAR(60)DEFAULT NULL COMMENT '触发器类型(时间) */5 * * * * ?',
`triggerstatus` INT(1)DEFAULT '0' COMMENT '任务状态:0关闭;1运行中;2暂停;',
`createuser` VARCHAR(15) DEFAULT NULL COMMENT '创建人员名称',
`createuserid` INT(11) DEFAULT NULL COMMENT '创建人员id',
`createtime` VARCHAR(30) DEFAULT NULL COMMENT '创建时间',
`updateuser` VARCHAR(15) DEFAULT NULL COMMENT '修改人员',
`updateuserid` INT(11) DEFAULT NULL COMMENT '修改人员id',
`updatetime` VARCHAR(30) DEFAULT NULL COMMENT '修改时间',
`del` INT(1) DEFAULT NULL COMMENT '是否删除(1:可用)',
`descript` VARCHAR(1024) COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='定时任务表'
Quartz Manager
package com.mlwy.controller.quartz;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.TriggerUtils;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.triggers.CronTriggerImpl;
public class QuartzManager {
private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();
/**
* 任务组名
*/
private static String JOB_GROUP_NAME = "JOBGROUP_NAME";
/**
* 触发器组名
*/
private static String TRIGGER_GROUP_NAME = "TRIGGERGROUP_NAME";
/**
* @Description: 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名
* @param jobName
* 任务名
* @param cls
* 任务
* @param //参考quartz说明文档
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void addJob(String jobName, Class cls, String cron) {
try {
Scheduler sched = gSchedulerFactory.getScheduler();
JobDetail job = JobBuilder.newJob(cls).withIdentity(jobName, JOB_GROUP_NAME).build();
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
// 按新的cronExpression表达式构建一个新的trigger
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, TRIGGER_GROUP_NAME)
.withSchedule(scheduleBuilder).build();
// 交给scheduler去调度
sched.scheduleJob(job, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
System.err.println("添加任务:"+jobName);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 添加一个定时任务
* @param jobName
* 任务名
* @param jobGroupName
* 任务组名
* @param triggerName
* 触发器名
* @param triggerGroupName
* 触发器组名
* @param jobClass
* 任务
* @param ,参考quartz说明文档
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
Class jobClass, String cron) {
try {
Scheduler sched = gSchedulerFactory.getScheduler();
JobDetail job = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
// 按新的cronExpression表达式构建一个新的trigger
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerName, triggerGroupName)
.withSchedule(scheduleBuilder).build();
sched.scheduleJob(job, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
* @param jobName
* @param
*/
public static void modifyJobTime(String jobName, String cron) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
sched.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:修改任务,(可以修改任务名,任务类,触发时间)
* 原理:移除原来的任务,添加新的任务
* @param oldJobName :原任务名
* @param jobName
* @param jobclass
* @param cron
* @date 2018年5月23日 上午9:13:10
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void modifyJob(String oldJobName, String jobName, Class jobclass, String cron) {
/*
* removeJob(oldJobName);
* addJob(jobName, jobclass, cron);
* System.err.println("修改任务"+oldJobName);
*/
TriggerKey triggerKey = TriggerKey.triggerKey(oldJobName, TRIGGER_GROUP_NAME);
JobKey jobKey = JobKey.jobKey(oldJobName, JOB_GROUP_NAME);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
Trigger trigger = (Trigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(jobKey);// 删除任务
System.err.println("移除任务:" + oldJobName);
JobDetail job = JobBuilder.newJob(jobclass).withIdentity(jobName, JOB_GROUP_NAME).build();
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
// 按新的cronExpression表达式构建一个新的trigger
Trigger newTrigger = TriggerBuilder.newTrigger().withIdentity(jobName, TRIGGER_GROUP_NAME)
.withSchedule(scheduleBuilder).build();
// 交给scheduler去调度
sched.scheduleJob(job, newTrigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
System.err.println("添加新任务:" + jobName);
}
System.err.println("修改任务【" + oldJobName + "】为:" + jobName);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 修改一个任务的触发时间
* @param triggerName
* @param triggerGroupName
* @param
*/
public static void modifyJobTime(String triggerName, String triggerGroupName, String cron) {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
// trigger已存在,则更新相应的定时设置
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
sched.resumeTrigger(triggerKey);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description 移除一个任务(使用默认的任务组名,触发器名,触发器组名)
* @param jobName
*/
public static void removeJob(String jobName) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME);
JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
Trigger trigger = (Trigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(jobKey);// 删除任务
System.err.println("移除任务:"+jobName);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 移除一个任务
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
*/
public static void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, triggerGroupName);
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(jobKey);// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:暂停一个任务(使用默认组名)
* @param jobName
*/
public static void pauseJob(String jobName) {
JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.pauseJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description:暂停一个任务
* @param jobName
* @param jobGroupName
*/
public static void pauseJob(String jobName, String jobGroupName) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.pauseJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description:恢复一个任务(使用默认组名)
* @param jobName
*/
public static void resumeJob(String jobName) {
JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.resumeJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description:恢复一个任务
* @param jobName
* @param jobGroupName
* @date 2018年5月17日 上午9:56:09
*/
public static void resumeJob(String jobName, String jobGroupName) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.resumeJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description:启动所有定时任务
*/
public static void startJobs() {
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description 关闭所有定时任务
*/
public static void shutdownJobs() {
try {
Scheduler sched = gSchedulerFactory.getScheduler();
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 立即运行任务,这里的立即运行,只会运行一次,方便测试时用。
* @param jobName
* @param
* @date 2018年5月17日 上午10:03:26
*/
public static void triggerJob(String jobName) {
JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.triggerJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 立即运行任务,这里的立即运行,只会运行一次,方便测试时用。
* @param jobName
* @param jobGroupName
* @date 2018年5月17日 上午10:03:26
*/
public static void triggerJob(String jobName, String jobGroupName) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
try {
Scheduler sched = gSchedulerFactory.getScheduler();
sched.triggerJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 获取任务状态
* NONE: 不存在
* NORMAL: 正常
* PAUSED: 暂停
* COMPLETE:完成
* ERROR : 错误
* BLOCKED : 阻塞
* @param jobName 触发器名
* @date 2018年5月21日 下午2:13:45
*/
public static String getTriggerState(String jobName){
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME);
String name = null;
try {
Scheduler sched = gSchedulerFactory.getScheduler();
TriggerState triggerState = sched.getTriggerState(triggerKey);
name = triggerState.name();
} catch (SchedulerException e) {
e.printStackTrace();
}
return name;
}
/**
* @Description:获取最近8次执行时间
* @param cron
* @date 2018年5月24日 下午5:13:03
*/
public static List<String> getRecentTriggerTime(String cron) {
List<String> list = new ArrayList<String>();
try {
CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
cronTriggerImpl.setCronExpression(cron);
// 这个是重点,一行代码搞定
List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 8);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (Date date : dates) {
list.add(dateFormat.format(date));
}
} catch (ParseException e) {
e.printStackTrace();
}
return list;
}
}
Quartz 启动
@RequestMapping("/able")
@ResponseBody
public AjaxJson able(HttpServletRequest request){
AjaxJson json = new AjaxJson();
try {
String id = request.getParameter("id");
QuartzVO vo = quartzService.selectByPrimaryKey(Integer.parseInt(id));
// 启动
vo.setTriggerstatus(1);
// 编写启动程序
Class clazz = null;
try {
clazz = Class.forName(vo.getClassname());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
QuartzManager.addJob(vo.getJobname(), clazz, vo.getTriggercron());
//处理自己的业务逻辑
String user = request.getSession().getAttribute("username").toString();
Integer uid = (Integer) request.getSession().getAttribute("userid");
vo.setUpdatetime(Util.getNow(null));
vo.setUpdateuser(user);
vo.setUpdateuserid(uid);
quartzService.updateByPrimaryKeySelective(vo);
json.setSuccess(true);
json.setMsg("启动成功");
}catch (Exception e){
json.setSuccess(false);
json.setMsg(e.toString());
e.printStackTrace();
}
return json;
}
测试Job
public class MyJob implements Job {
private static final Logger log = Logger.getLogger(MyJob.class);
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
log.info("任务运行开始-------- start --------");
try {
String jobName = context.getJobDetail().getKey().getName();
String jobGroup = context.getJobDetail().getKey().getGroup();
String triggerName = context.getTrigger().getKey().getName();
String triggerGroup = context.getTrigger().getKey().getGroup();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
log.info("触发器Key:" + triggerName + ".." + triggerGroup + " 正在执行...");
log.info("任务Key:" + jobName + ".." + jobGroup + " 正在执行,执行时间: "
+ dateFormat.format(Calendar.getInstance().getTime()));
}catch (Exception e) {
log.info("捕获异常==="+e);
}
log.info("任务运行结束-------- end --------");
}
}
本地测试
public class LoadTask {
public static void main(String[] args) {
System.err.println("【系统启动】");
String corn = "0/5 * * * * ?";
//QuartzManager.addJob("job1", "jobGooup", "trigger1", "triggerGroup", MyJob.class, corn);
QuartzManager.addJob("job1", MyJob.class, corn);
System.err.println("添加任务一");
QuartzManager.getTriggerState("jobs");
//睡眠一分钟
try {
Thread.sleep(60L * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
QuartzManager.modifyJobTime("job1", "0/3 * * * * ?");
System.out.println("修改触发时间");
try {
Thread.sleep(15L * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
QuartzManager.removeJob("job1");
//QuartzManager.removeJob("job1", "jobGooup", "trigger1", "triggerGroup");
System.out.println("删除任务");
try {
Thread.sleep(5L * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("【添加定时任务】");
QuartzManager.addJob("job1", MyJob.class, corn);
//QuartzManager.shutdownJobs();
//System.out.println("停止所有任务");
try {
Thread.sleep(5L * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("【暂停定时任务】");
QuartzManager.pauseJob("job1");
System.out.println("【立即运行一次】");
QuartzManager.triggerJob("job1");
try {
Thread.sleep(5L * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("【恢复定时任务】");
QuartzManager.resumeJob("job1");
try {
Thread.sleep(5L * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
QuartzManager.shutdownJobs();
}
}