中文文档:
Quartz中文文档
w3cschool的quartz教程
常用方法
增删改查
package com.projects.springboot.messagecenter.task;
import com.projects.springboot.common.utils.DateHelper;
import com.projects.springboot.common.utils.StringHelper;
import com.projects.springboot.messagecenter.util.CronDateUtils;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import static org.quartz.JobBuilder.newJob;
/**
* @author LinJie
* @version V2.0
* @Description: 定时任务管理类
* @ClassName: QuartzManager
* @Copyright: Copyright (c) 2017
* Date 2017-6-26 下午03:15:52
*/
@Component
public class QuartzManager {
/**
* LOGGER
*/
private static final Logger LOGGER = LoggerFactory.getLogger(QuartzManager.class);
/**
* schedulerFactory
*/
@Autowired
private SchedulerFactoryBean schedulerFactory;
/**
* JOB_GROUP_NAME
*/
private static final String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME";
/**
* TRIGGER_GROUP_NAME
*/
private static final String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME";
/**
* @param jobName 任务名
* @param jobClass 任务处理类
* @param time 时间设置,参考quartz说明文档
* @Description: 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author LinJie
* @date 2014-6-26 下午03:47:44
* @version V2.0
*/
public void addJob(String jobName, Class jobClass, String time) {
try {
Scheduler sched = schedulerFactory.getScheduler();
// 任务名,任务组
JobDetail job = newJob(jobClass).withIdentity(jobName, JOB_GROUP_NAME).build();
// 触发器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
.cronSchedule(transCronExperssionFromTimestamp(time));
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName, TRIGGER_GROUP_NAME)
.withSchedule(cronScheduleBuilder).build();
sched.scheduleJob(job, cronTrigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
LOGGER.error("创建定时任务失败" + e);
throw new RuntimeException(e);
}
}
/**
* @param jobName 任务名
* @param jobClass 任务处理类
* @param cronExperssion cron表达式
* @Description: 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author LinJie
* @date 2017-11-14 下午03:47:44
* @throws Exception Exception
* @version V2.0
* @return boolean
*/
public boolean addJobWithCronExperssion(String jobName, Class jobClass, String cronExperssion) throws Exception {
// 通过SchedulerFactory获取一个调度器实例
Scheduler sched = schedulerFactory.getScheduler();
//构建job信息
JobDetail job = newJob(jobClass).withIdentity(jobName, JOB_GROUP_NAME).build();
//表达式调度构建器(即任务执行的时间)
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExperssion);
//按新的cronExpression表达式构建一个新的trigger
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName, TRIGGER_GROUP_NAME)
.withSchedule(cronScheduleBuilder).build();
try {
Date ft = sched.scheduleJob(job, cronTrigger);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
LOGGER.info(job.getKey() + " 已被安排执行于: " + sdf.format(ft) + ",并且以如下重复规则重复执行: "
+ cronTrigger.getCronExpression());
// 启动调度器
sched.start();
} catch (Exception e) {
LOGGER.error("创建定时任务失败" + e);
throw new Exception(e);
}
return true;
}
/**
* @param jobName 任务名
* @param jobClass 任务处理类
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param time 时间设置,参考quartz说明文档
* @Description: 添加一个定时任务
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author Comsys-LZP
* @date 2014-6-26 下午03:48:15
* @version V2.0
*/
@SuppressWarnings("unchecked")
public void addJob(String jobName, Class jobClass, String jobGroupName,
String triggerName, String triggerGroupName,
String time) {
try {
Scheduler sched = schedulerFactory.getScheduler();
JobDetail job = newJob(jobClass)
.withIdentity(jobName, jobGroupName) // 任务名,任务组
.build();
// 触发器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
.cronSchedule(transCronExperssionFromTimestamp(time));
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerName, triggerGroupName)
.withSchedule(cronScheduleBuilder).build();
sched.scheduleJob(job, cronTrigger);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @param jobName String
* @param time String
* @Description: 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author Comsys-LZP
* @date 2014-6-26 下午03:49:21
* @version V2.0
*/
@SuppressWarnings("unchecked")
public void modifyJob(String jobName, String time) {
try {
Scheduler sched = schedulerFactory.getScheduler();
CronTrigger trigger = (CronTrigger) sched.getTrigger(TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME));
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
String newTime = transCronExperssionFromTimestamp(time);
if (!oldTime.equalsIgnoreCase(newTime)) {
JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, JOB_GROUP_NAME));
Class objJobClass = jobDetail.getJobClass();
removeJob(jobName);
addJob(jobName, objJobClass, time);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @param jobName 任务名
* @param cronExperssion cron表达式
* @Description: 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author LinJie
* @date 2017-11-14 下午03:47:44
* @version V2.0
* @return boolean
* @throws Exception Exception
*/
public boolean modifyJobWithCronExperssion(String jobName, String cronExperssion) throws Exception {
try {
// 通过SchedulerFactory获取一个调度器实例
Scheduler sched = schedulerFactory.getScheduler();
if (StringHelper.isNotEmpty(cronExperssion)) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME);
// 表达式调度构建器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
.cronSchedule(cronExperssion);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return false;
}
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(cronScheduleBuilder).startAt(new Date()).build();
// 按新的trigger重新设置job执行
Date ft = sched.rescheduleJob(triggerKey, trigger);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
LOGGER.info(jobName + " 已被安排执行于: " + sdf.format(ft) + ",并且以如下重复规则重复执行: "
+ trigger.getCronExpression());
// 启动
sched.start();
// 停用
// sched.pauseJob(JobKey.jobKey(jobName, JOB_GROUP_NAME));
}
} catch (Exception e) {
LOGGER.error("更新定时任务失败" + e);
throw new Exception(e);
}
return true;
}
/**
* @param triggerName String
* @param triggerGroupName String
* @param time String
* @Description: 修改一个任务的触发时间
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author Comsys-LZP
* @date 2014-6-26 下午03:49:37
* @version V2.0
*/
public void modifyJob(String triggerName,
String triggerGroupName, String time) {
try {
Scheduler sched = schedulerFactory.getScheduler();
CronTrigger trigger = (CronTrigger) sched.getTrigger(TriggerKey.triggerKey(triggerName,
TRIGGER_GROUP_NAME));
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
String newTime = transCronExperssionFromTimestamp(time);
if (!oldTime.equalsIgnoreCase(newTime)) {
// 修改时间
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(newTime);
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerName, triggerGroupName)
.withSchedule(cronScheduleBuilder).build();
// 重启触发器
sched.resumeTrigger(TriggerKey.triggerKey(triggerName, triggerGroupName));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @param jobName String
* @Description: 移除一个任务(使用默认的任务组名,触发器名,触发器组名)
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author Comsys-LZP
* @date 2014-6-26 下午03:49:51
* @version V2.0
* @return boolean
* @throws Exception Exception
*/
public boolean removeJob(String jobName) throws Exception {
try {
// 通过SchedulerFactory获取一个调度器实例
Scheduler sched = schedulerFactory.getScheduler();
sched.pauseTrigger(TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME)); // 停止触发器
sched.unscheduleJob(TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME)); // 移除触发器
sched.deleteJob(JobKey.jobKey(jobName, JOB_GROUP_NAME)); // 删除任务
} catch (Exception e) {
LOGGER.error("删除定时任务失败" + e);
throw new Exception(e);
}
return true;
}
/**
* @param jobName String
* @param jobGroupName String
* @param triggerName String
* @param triggerGroupName String
* @Description: 移除一个任务
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author Comsys-LZP
* @date 2014-6-26 下午03:50:01
* @version V2.0
*/
public void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
Scheduler sched = schedulerFactory.getScheduler();
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);
}
}
/**
* @Description:启动所有定时任务
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author Comsys-LZP
* @date 2014-6-26 下午03:50:18
* @version V2.0
*/
public void startJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author Comsys-LZP
* @date 2014-6-26 下午03:50:26
* @version V2.0
*/
public void shutdownJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* transCronExperssionFromTimestamp
*
* @param time String
* @return java.lang.String
* @Description 由时间戳生成Cron表达式
* @Date 2017/7/28 18:56
*/
private String transCronExperssionFromTimestamp(String time) {
// 根据time时间戳生成格式化条件
Date date = DateHelper.transDate(time, DateHelper.DEFAULT_DATETIME_FORMAT);
String cron = CronDateUtils.getCron(date);
LOGGER.info("CronExpression: " + cron);
return cron;
}
/**
* @param jobName String
* @Description: 暂停一个任务(使用默认的任务组名,触发器名,触发器组名)
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author Comsys-LZP
* @date 2014-6-26 下午03:49:51
* @version V2.0
* @return boolean
* @throws Exception Exception
*/
public boolean pauseJob(String jobName) throws Exception {
try {
// 通过SchedulerFactory获取一个调度器实例
Scheduler sched = schedulerFactory.getScheduler();
sched.pauseJob(JobKey.jobKey(jobName, JOB_GROUP_NAME));
} catch (Exception e) {
LOGGER.error("暂停定时任务失败" + e);
throw new Exception(e);
}
return true;
}
/**
* @param jobName String
* @Description: 恢复一个任务(使用默认的任务组名,触发器名,触发器组名)
* @Title: QuartzManager.java
* @Copyright: Copyright (c) 2014
* @author Comsys-LZP
* @date 2014-6-26 下午03:49:51
* @version V2.0
* @return boolean
* @throws Exception Exception
*/
public boolean resumeJob(String jobName) throws Exception {
try {
// 通过SchedulerFactory获取一个调度器实例
Scheduler sched = schedulerFactory.getScheduler();
sched.resumeJob(JobKey.jobKey(jobName, JOB_GROUP_NAME));
} catch (Exception e) {
LOGGER.error("暂停定时任务失败" + e);
throw new Exception(e);
}
return true;
}
}
service层简单封装
package com.projects.springboot.messagecenter.service;
import com.projects.springboot.messagecenter.domain.QuartzJobParam;
import com.projects.springboot.messagecenter.interfaces.IQuartzManageService;
import com.projects.springboot.messagecenter.task.QuartzManager;
import com.projects.springboot.messagecenter.task.job.SampleJob;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author LinJie
* @version $Id: AssignmentService.java, v 0.1 2017/7/15 8:51 LinJie Exp $
*/
@Service
@Transactional(readOnly = true)
public class QuartzManageService implements IQuartzManageService {
/**
* Logger
*/
private static final Logger LOGGER = Logger.getLogger(QuartzManageService.class);
/**
* QuartzManager
*/
@Autowired
private QuartzManager quartzManager;
/**
* 创建定时任务
*
* @param param QuartzJobParam
* @return boolean
*/
@Override
public boolean addJob(QuartzJobParam param) {
boolean isSuccess = false;
try {
isSuccess = quartzManager.addJobWithCronExperssion(param.getJobId(), SampleJob.class,
param.getCronExperssion());
} catch (Exception e) {
e.printStackTrace();
}
return isSuccess;
}
/**
* 修改定时任务
*
* @param param QuartzJobParam
* @return boolean
*/
@Override
public boolean modifyJob(QuartzJobParam param) {
boolean isSuccess = false;
try {
isSuccess = quartzManager.modifyJobWithCronExperssion(param.getJobId(), param.getCronExperssion());
} catch (Exception e) {
e.printStackTrace();
}
return isSuccess;
}
/**
* 删除定时任务
*
* @param param QuartzJobParam
* @return boolean
*/
@Override
public boolean removeJob(QuartzJobParam param) {
boolean isSuccess = false;
try {
isSuccess = quartzManager.removeJob(param.getJobId());
} catch (Exception e) {
e.printStackTrace();
}
return isSuccess;
}
/**
* 暂停定时任务
*
* @param param QuartzJobParam
* @return boolean
*/
@Override
public boolean pauseJob(QuartzJobParam param) {
boolean isSuccess = false;
try {
isSuccess = quartzManager.pauseJob(param.getJobId());
} catch (Exception e) {
e.printStackTrace();
}
return isSuccess;
}
/**
* 恢复定时任务
*
* @param param QuartzJobParam
* @return boolean
*/
@Override
public boolean resumeJob(QuartzJobParam param) {
boolean isSuccess = false;
try {
isSuccess = quartzManager.resumeJob(param.getJobId());
} catch (Exception e) {
e.printStackTrace();
}
return isSuccess;
}
}
说明:每个定时任务都必须有一个分组,名称和corn表达式,corn表达式也就是定时任务的触发时间,关于corn表达式格式以及含义可以参考一些网络资源。每个定时任务都有一个入口类在这里我把类名当成定时任务的分组名称,例如:只要创建定时任务的分组是JobOne的都会执行JobOne这个任务类里面的逻辑。如果定时任务需要额外的参数可以使用JobDataMap传递参数,当然也可以从数据库中获取需要的数据。@PersistJobDataAfterExecution和@DisallowConcurrentExecution注解是不让某个定时任务并发执行,只有等当前任务完成下一个任务才会去执行。
总结
如果实现不同业务逻辑的job,可以创建多个job实例
与业务实现的整体思路:将一个业务id设置job的值,设置时间间隔的Trigger,放到scheduler并启动。到时间点了,取出业务id,进行相应的业务操作即可,此步可走消息队列,异步进行。
扩展:
https://blog.csdn.net/pengjunlee/article/details/78965877
https://blog.csdn.net/pengjunlee/article/details/78715272
https://blog.csdn.net/bicheng4769/article/details/81097305
多job示例