1.需求场景
实现动态定时任务。通过修改cron表达式,实时更新任务执行时间。
2.环境
quartz-2.1.7 Spring 3.2 Mybatis3.2
3.解决方法
(1)配置quartz文件
# 配置任务信息
#============================================================================
org.quartz.scheduler.instanceName: quartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
#============================================================================
#配置线程池
#============================================================================
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 2
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
#=====================================================================================
#配置为持久化到数据库的方式
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore(定时任务信息保存在内存)
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties:true
#============================================================================
#非集群模式
#============================================================================
org.quartz.jobStore.isClustered = false
#配置表的前缀
org.quartz.jobStore.tablePrefix:QRTZ_
#============================================================================
# 配置数据源
#============================================================================
org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL:jdbc:mysql://127.0.0.1:3306/task
org.quartz.dataSource.qzDS.user:root
org.quartz.dataSource.qzDS.password:123456
#(由于quartz默认是使用c3p0连接池,本例没有使用,故自定义dbcp连接池实现)
org.quartz.dataSource.qzDS.connectionProvider.class:com.task.util.DBCPConnectionProvider
(2)使用dbcp提供连接池
package com.task.util;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbcp.BasicDataSource;
import org.quartz.SchedulerException;
import org.quartz.utils.ConnectionProvider;
public class DBCPConnectionProvider implements ConnectionProvider {
private BasicDataSource datasource;
// JDBC驱动
public String driver;
// JDBC连接串
public String URL;
// 数据库用户名
public String user;
// 数据库用户密码
public String password;
public void initialize() throws SQLException,
SchedulerException {
if (URL == null) {
throw new SQLException(
"DBPool could not be created: DB URL cannot be null");
}
if (driver == null) {
throw new SQLException("DBPool '" + URL
+ "' could not be created: "
+ "DB driver class name cannot be null!");
}
datasource = new BasicDataSource();
datasource.setDriverClassName(driver);
datasource.setUrl(URL);
datasource.setUsername(user);
datasource.setPassword(password);
datasource.setMaxActive(50);
datasource.setMinIdle(1);
datasource.setMaxWait(5000);
datasource.setValidationQuery("SELECT 1");
datasource.setTestOnBorrow(false);
datasource.setTestOnReturn(false);
datasource.setTimeBetweenEvictionRunsMillis(1800000);
}
@Override
public Connection getConnection() throws SQLException {
return datasource.getConnection();
}
public void shutdown() throws SQLException {
datasource.close();
}
public BasicDataSource getDatasource() {
return datasource;
}
public void setDatasource(BasicDataSource datasource) {
this.datasource = datasource;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getURL() {
return URL;
}
public void setURL(String uRL) {
URL = uRL;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
(3)Quartz与Spring集成Job自动注入Spring容器托管对象
package com.task.job;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle)
throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
(4)spring.xml配置
(5)定义job
@Component
public class AutoJob implements Job {
@Autowired
private ToolService toolService;
@Override
public void execute(JobExecutionContext ctx) throws JobExecutionException {
//获得参数对象
JobDataMap jmap = ctx.getJobDetail().getJobDataMap();
//获取配置id
String id = jmap.getString("jobName");
//查询配置信息 并执行 查询。
toolService.runTask(Integer.parseInt(id));
}
(6)任务增删改查操作
package com.task.serviceImpl.task;
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.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.task.service.task.QuartzService;
@Service("quartzService")
public class QuartzServiceImpl implements QuartzService {
@Autowired
private Scheduler quartzScheduler;
@Override
public void addJob(String jobName, String jobGroupName, String triggerName,
String triggerGroupName, Class cls, String cron) {
try {
// 获取调度器
Scheduler sched = quartzScheduler;
// 创建一项作业
JobDetail job = JobBuilder.newJob(cls)
.usingJobData("jobName", jobName)
.withIdentity(jobName, jobGroupName).build();
// 创建一个触发器
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerName, triggerGroupName)
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
// 告诉调度器使用该触发器来安排作业
sched.scheduleJob(job, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改定时器任务信息
*/
@Override
public boolean modifyJobTime(String oldjobName, String oldjobGroup,
String oldtriggerName, String oldtriggerGroup, String jobName,
String jobGroup, String triggerName, String triggerGroup,
String cron) {
try {
Scheduler sched = quartzScheduler;
CronTrigger trigger = (CronTrigger) sched.getTrigger(TriggerKey
.triggerKey(oldtriggerName, oldtriggerGroup));
if (trigger == null) {
return false;
}
JobKey jobKey = JobKey.jobKey(oldjobName, oldjobGroup);
TriggerKey triggerKey = TriggerKey.triggerKey(oldtriggerName,
oldtriggerGroup);
JobDetail job = sched.getJobDetail(jobKey);
Class jobClass = job.getJobClass();
// 停止触发器
sched.pauseTrigger(triggerKey);
// 移除触发器
sched.unscheduleJob(triggerKey);
// 删除任务
sched.deleteJob(jobKey);
addJob(jobName, jobGroup, triggerName, triggerGroup, jobClass, cron);
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void modifyJobTime(String triggerName, String triggerGroupName,
String time) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) quartzScheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(time));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
quartzScheduler.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
Scheduler sched = quartzScheduler;
// 停止触发器
sched.pauseTrigger(TriggerKey.triggerKey(triggerName,
triggerGroupName));
// 移除触发器
sched.unscheduleJob(TriggerKey.triggerKey(triggerName,
triggerGroupName));
// 删除任务
sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void startSchedule() {
try {
Scheduler sched = quartzScheduler;
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void shutdownSchedule() {
try {
Scheduler sched = quartzScheduler;
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void pauseJob(String jobName, String jobGroupName) {
try {
quartzScheduler.pauseJob(JobKey.jobKey(jobName, jobGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@Override
public void resumeJob(String jobName, String jobGroupName) {
try {
quartzScheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
public interface QuartzService {
public void addJob(String jobName, String jobGroupName, String triggerName,
String triggerGroupName, Class cls, String cron);
public boolean modifyJobTime(String oldjobName, String oldjobGroup,
String oldtriggerName, String oldtriggerGroup, String jobName,
String jobGroup, String triggerName, String triggerGroup,
String cron);
public void modifyJobTime(String triggerName, String triggerGroupName,
String cron);
public void pauseJob(String jobName, String jobGroupName);
public void resumeJob(String jobName, String jobGroupName);
public void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName);
public void startSchedule();
public void shutdownSchedule();
}
@Controller
public class QuartzAction {
@Autowired
private Scheduler quartzScheduler;
@Autowired
private QuartzService quartzService;
/**
* 定时列表页
*
* @return
* @throws SchedulerException
*/
@RequestMapping(value = "/listJob")
public String listJob(HttpServletRequest request,
HttpServletResponse response) throws SchedulerException {
List jobInfos = this.getSchedulerJobInfo();
request.setAttribute("jobInfos", jobInfos);
return "listjob";
}
/**
* 跳转到新增
*
* @return
* @throws SchedulerException
* @throws ClassNotFoundException
*/
@RequestMapping(value = "/toAdd")
public String toAdd(HttpServletRequest request, HttpServletResponse response)
throws SchedulerException {
return "addjob";
}
/**
* 新增job
*
* @return
* @throws SchedulerException
* @throws ClassNotFoundException
*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String add(HttpServletRequest request, HttpServletResponse response)
throws SchedulerException, ClassNotFoundException {
String jobName = request.getParameter("jobName");
String jobGroupName = request.getParameter("jobGroupName");
String triggerName = request.getParameter("triggerName");
String triggerGroupName = request.getParameter("triggerGroupName");
String clazz = request.getParameter("clazz");
Class> cls = Class.forName(clazz);
String cron = request.getParameter("cron");
quartzService.addJob(jobName, jobGroupName, triggerName,
triggerGroupName, cls, cron);
request.setAttribute("message", "添加任务成功!");
request.setAttribute("opName", "添加任务!");
return "message";
}
/**
* 跳转到编辑
*
* @return
* @throws SchedulerException
* @throws ClassNotFoundException
*/
@RequestMapping(value = "/toEdit")
public String toEdit(HttpServletRequest request,
HttpServletResponse response) throws SchedulerException {
String jobName = request.getParameter("jobName");
String jobGroup = request.getParameter("jobGroup");
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
JobDetail jd = quartzScheduler.getJobDetail(jobKey);
@SuppressWarnings("unchecked")
List triggers = (List) quartzScheduler
.getTriggersOfJob(jobKey);
CronTrigger trigger = triggers.get(0);
TriggerKey triggerKey = trigger.getKey();
String cron = trigger.getCronExpression();
Map pd = new HashMap();
pd.put("jobName", jobKey.getName());
pd.put("jobGroup", jobKey.getGroup());
pd.put("triggerName", triggerKey.getName());
pd.put("triggerGroupName", triggerKey.getGroup());
pd.put("cron", cron);
pd.put("clazz", jd.getJobClass().getCanonicalName());
request.setAttribute("pd", pd);
request.setAttribute("msg", "edit");
return "editjob";
}
public void modifyJobTime(String triggerName, String triggerGroupName, String cron) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) quartzScheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
trigger = (CronTrigger) triggerBuilder.build();
quartzScheduler.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 编辑job
*
* @return
* @throws SchedulerException
* @throws ClassNotFoundException
*/
@RequestMapping(value = "/edit", method = RequestMethod.POST)
public String edit(HttpServletRequest request, HttpServletResponse response)
throws SchedulerException, ClassNotFoundException {
String jobName = request.getParameter("jobName");
String jobGroupName = request.getParameter("jobGroupName");
String triggerName = request.getParameter("triggerName");
String triggerGroupName = request.getParameter("triggerGroupName");
String clazz = request.getParameter("clazz");
@SuppressWarnings("unused")
Class> cls = Class.forName(clazz);
String cron = request.getParameter("cron");
String oldjobName = request.getParameter("oldjobName");
String oldjobGroup = request.getParameter("oldjobGroup");
String oldtriggerName = request.getParameter("oldtriggerName");
String oldtriggerGroup = request.getParameter("oldtriggerGroup");
boolean result = quartzService.modifyJobTime(oldjobName, oldjobGroup,
oldtriggerName, oldtriggerGroup, jobName, jobGroupName,
triggerName, triggerGroupName, cron);
if (result) {
request.setAttribute("message", "修改任务成功!");
} else {
request.setAttribute("message", "修改任务失败!");
}
request.setAttribute("opName", "更新任务!");
return "quartz/message";
}
@RequestMapping(value = "/pauseJob", method = RequestMethod.POST)
@ResponseBody
public String pauseJob(@RequestParam("jobName") String jobName,
@RequestParam("jobGroupName") String jobGroupName) {
JSONObject json = new JSONObject();
if (StringUtils.isEmpty(jobName) || StringUtils.isEmpty(jobGroupName)) {
json.put("status", "wrong");
} else {
quartzService.pauseJob(jobName, jobGroupName);
json.put("status", "success");
}
return json.toString();
}
@RequestMapping(value = "/resumeJob", method = RequestMethod.POST)
@ResponseBody
public String resumeJob(@RequestParam("jobName") String jobName,
@RequestParam("jobGroupName") String jobGroupName) {
JSONObject json = new JSONObject();
if (StringUtils.isEmpty(jobName) || StringUtils.isEmpty(jobGroupName)) {
json.put("status", "wrong");
} else {
quartzService.resumeJob(jobName, jobGroupName);
json.put("status", "success");
}
return json.toString();
}
@RequestMapping(value = "/deleteJob", method = RequestMethod.POST)
@ResponseBody
public String deleteJob(@RequestParam("jobName") String jobName,
@RequestParam("jobGroupName") String jobGroupName,
@RequestParam("triggerName") String triggerName,
@RequestParam("triggerGroupName") String triggerGroupName) {
JSONObject json = new JSONObject();
if (StringUtils.isEmpty(jobName) || StringUtils.isEmpty(jobGroupName)
|| StringUtils.isEmpty(triggerName)
|| StringUtils.isEmpty(triggerGroupName)) {
json.put("status", "wrong");
} else {
quartzService.removeJob(jobName, jobGroupName, triggerName,
triggerGroupName);
json.put("status", "success");
}
return json.toString();
}
private List getSchedulerJobInfo() throws SchedulerException {
List jobInfos = new ArrayList();
List triggerGroupNames = quartzScheduler.getTriggerGroupNames();
for (String triggerGroupName : triggerGroupNames) {
Set triggerKeySet = quartzScheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(triggerGroupName));
for (TriggerKey triggerKey : triggerKeySet) {
Trigger t = quartzScheduler.getTrigger(triggerKey);
if (t instanceof CronTrigger) {
CronTrigger trigger = (CronTrigger) t;
JobKey jobKey = trigger.getJobKey();
JobDetail jd = quartzScheduler.getJobDetail(jobKey);
JobEntity jobInfo = new JobEntity();
jobInfo.setJobName(jobKey.getName());
jobInfo.setJobGroup(jobKey.getGroup());
jobInfo.setTriggerName(triggerKey.getName());
jobInfo.setTriggerGroupName(triggerKey.getGroup());
jobInfo.setCronExpr(trigger.getCronExpression());
jobInfo.setNextFireTime(trigger.getNextFireTime());
jobInfo.setPreviousFireTime(trigger.getPreviousFireTime());
jobInfo.setStartTime(trigger.getStartTime());
jobInfo.setEndTime(trigger.getEndTime());
jobInfo.setJobClass(jd.getJobClass().getCanonicalName());
// jobInfo.setDuration(Long.parseLong(jd.getDescription()));
Trigger.TriggerState triggerState = quartzScheduler.getTriggerState(trigger.getKey());
jobInfo.setJobStatus(triggerState.toString());// NONE无,
// NORMAL正常,
// PAUSED暂停,
// COMPLETE完成,
// ERROR错误,
// BLOCKED阻塞
JobDataMap map = quartzScheduler.getJobDetail(jobKey).getJobDataMap();
if (null != map && map.size() != 0) {
//jobInfo.setCount(Integer.parseInt((String) map.get("count")));
//jobInfo.setJobDataMap(map);
} else {
jobInfo.setJobDataMap(new JobDataMap());
}
jobInfos.add(jobInfo);
}
}
}
return jobInfos;
}
}
}
参考链接:
https://blog.csdn.net/lkl_csdn/article/details/73613033 (quartz 原理到应用)
https://blog.csdn.net/u010377605/article/details/77801896/ (quartz动态定时任务)
https://blog.csdn.net/qq_38974131/article/details/77801615 (quartz 集成 spring+springmvc+jpa)
https://www.cnblogs.com/davidwang456/p/4205237.html (quartz 原理分析)
https://blog.csdn.net/zhouhua0104/article/details/46560555 (Quartz+Spring 实现任务监控)