1、Timer:这是Java自带的java.util.Timer
类,这个类允许你调度一个java.util.TimerTask
任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行,一般使用比较少
2、Spring Task:Spring3.0以后自带的Task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多
3、ScheduledExecutorService:也是jdk自带的一个类,是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行的,互不影响
4、Quartz:这是一个功能比较强大的调度器,可以让你的程序在指定的时间执行,也可以按照某一个频度执行,配置起来稍显复杂
5、xxl-job:XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。xxl三个字母是其开发者许雪里名字的缩写。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
@EnableScheduling
@Component
public class TimingService {
private int count=0;
//使用cron表达式,每天23点执行一次
@Scheduled(cron="0 0 23 * *")
public void timingTask() throws Exception {
System.out.println("this is scheduler task runing "+(count++));
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* @描述 执行定时任务的线程池配置类
* @创建人 yhgh
* @创建时间 2022/8/26 14:01
*/
@Configuration
public class SchedulingConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
// 定时任务执行线程池核心线程数
taskScheduler.setPoolSize(4);
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
return taskScheduler;
}
}
import java.util.concurrent.ScheduledFuture;
/**
* @描述 ScheduledFuture的包装类。ScheduledFuture是ScheduledExecutorService定时任务线程池的执行结果。
* @创建人 yhgh
* @创建时间 2022/8/26 14:03
*/
public final class ScheduledTask {
public volatile ScheduledFuture<?> future;
/**
* 取消定时任务
*/
public void cancel() {
ScheduledFuture<?> future = this.future;
if (future != null) {
future.cancel(true);
}
}
}
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @描述 用于从Spring容器中操作Bean
* @创建人 yhgh
* @创建时间 2022/8/26 14:13
*/
@Component
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
public static <T> T getBean(String name, Class<T> requiredType) {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}
public static Class<? extends Object> getType(String name) {
return applicationContext.getType(name);
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* @描述 Runnable接口实现类,被定时任务线程池调用,用来执行指定bean里面的方法。
* @创建人 yhgh
* @创建时间 2022/8/26 14:04
*/
public class SchedulingRunnable implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);
private String beanName;
private String methodName;
private String params;
public SchedulingRunnable(String beanName, String methodName) {
this(beanName, methodName, null);
}
public SchedulingRunnable(String beanName, String methodName, String params) {
this.beanName = beanName;
this.methodName = methodName;
this.params = params;
}
@Override
public void run() {
logger.info("定时任务开始执行 - bean:{},方法:{},参数:{}", beanName, methodName, params);
long startTime = System.currentTimeMillis();
try {
Object target = SpringContextUtils.getBean(beanName);
Method method = null;
if (StringUtils.hasText(params)) {
method = target.getClass().getDeclaredMethod(methodName, String.class);
} else {
method = target.getClass().getDeclaredMethod(methodName);
}
ReflectionUtils.makeAccessible(method);
if (StringUtils.hasText(params)) {
method.invoke(target, params);
} else {
method.invoke(target);
}
} catch (Exception ex) {
logger.error(String.format("定时任务执行异常 - bean:%s,方法:%s,参数:%s ", beanName, methodName, params), ex);
}
long times = System.currentTimeMillis() - startTime;
logger.info("定时任务执行结束 - bean:{},方法:{},参数:{},耗时:{} 毫秒", beanName, methodName, params, times);
}
/**
* 重写equals方法,使用beanName、methodName、params比较
* @param o
* @return
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SchedulingRunnable that = (SchedulingRunnable) o;
if (params == null) {
return beanName.equals(that.beanName) &&
methodName.equals(that.methodName) &&
that.params == null;
}
return beanName.equals(that.beanName) &&
methodName.equals(that.methodName) &&
params.equals(that.params);
}
@Override
public int hashCode() {
if (params == null) {
return Objects.hash(beanName, methodName);
}
return Objects.hash(beanName, methodName, params);
}
}
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @描述 添加定时任务注册类,用来增加、删除定时任务。
* @创建人 yhgh
* @创建时间 2022/8/26 14:18
*/
@Component
public class CronTaskRegistrar implements DisposableBean {
private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);
@Autowired
private TaskScheduler taskScheduler;
public TaskScheduler getScheduler() {
return this.taskScheduler;
}
/**
* 添加任务
* @param task
* @param cronExpression
*/
public void addCronTask(Runnable task, String cronExpression) {
addCronTask(new CronTask(task, cronExpression));
}
/**
* 将定时任务添加进Map中
* @param cronTask
*/
private void addCronTask(CronTask cronTask) {
if (cronTask != null) {
Runnable task = cronTask.getRunnable();
if (this.scheduledTasks.containsKey(task)) {
removeCronTask(task);
}
this.scheduledTasks.put(task, scheduleCronTask(cronTask));
}
}
/**
* 删除任务
* @param task
*/
public void removeCronTask(Runnable task) {
ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
if (scheduledTask != null)
scheduledTask.cancel();
}
/**
* 对cronTask进行包装,并执行定时任务
* @param cronTask
* @return
*/
private ScheduledTask scheduleCronTask(CronTask cronTask) {
ScheduledTask scheduledTask = new ScheduledTask();
scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
return scheduledTask;
}
@Override
public void destroy() {
for (ScheduledTask task : this.scheduledTasks.values()) {
task.cancel();
}
this.scheduledTasks.clear();
}
}
CREATE TABLE `system_task` (
`task_id` varchar(70) NOT NULL COMMENT '任务id',
`bean_name` varchar(100) DEFAULT NULL COMMENT 'bean名称',
`method_name` varchar(100) DEFAULT NULL COMMENT '方法名称',
`method_params` varchar(255) DEFAULT NULL COMMENT '方法参数',
`cron_expression` varchar(255) DEFAULT NULL COMMENT 'cron表达式',
`task_status` tinyint(1) DEFAULT NULL COMMENT '状态(1正常 0暂停)',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`task_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统定时任务';
import java.util.Date;
import java.io.Serializable;
/**
* 系统定时任务(SystemTask)实体类
*
* @since 2022-08-26 15:29:44
*/
public class SystemTask implements Serializable {
private static final long serialVersionUID = -54922456361386370L;
/**
* 任务id
*/
private String taskId;
/**
* bean名称
*/
private String beanName;
/**
* 方法名称
*/
private String methodName;
/**
* 方法参数
*/
private String methodParams;
/**
* cron表达式
*/
private String cronExpression;
/**
* 状态(1正常 0暂停)
*/
private Boolean taskStatus;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getMethodParams() {
return methodParams;
}
public void setMethodParams(String methodParams) {
this.methodParams = methodParams;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public Boolean getTaskStatus() {
return taskStatus;
}
public void setTaskStatus(Boolean taskStatus) {
this.taskStatus = taskStatus;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 系统定时任务(SystemTask)表数据库访问层
*
* @since 2022-08-26 15:29:43
*/
@Mapper
public interface SystemTaskDao {
/**
* 通过ID查询单条数据
*
* @param taskId 主键
* @return 实例对象
*/
SystemTask queryById(String taskId);
/**
* 新增数据
*
* @param systemTask 实例对象
* @return 影响行数
*/
int insert(SystemTask systemTask);
/**
* 修改数据
*
* @param systemTask 实例对象
* @return 影响行数
*/
int update(SystemTask systemTask);
/**
* 通过主键删除数据
*
* @param taskId 主键
* @return 影响行数
*/
int deleteById(String taskId);
/**
* 根据任务状态查询所有任务
* @param status
* @return
*/
List<SystemTask> selectTasksByStatus(@Param("taskStatus")Boolean status);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.ygang.task.dao.SystemTaskDao">
<resultMap type="top.ygang.task.entity.SystemTask" id="SystemTaskMap">
<result property="taskId" column="task_id" jdbcType="VARCHAR"/>
<result property="beanName" column="bean_name" jdbcType="VARCHAR"/>
<result property="methodName" column="method_name" jdbcType="VARCHAR"/>
<result property="methodParams" column="method_params" jdbcType="VARCHAR"/>
<result property="cronExpression" column="cron_expression" jdbcType="VARCHAR"/>
<result property="taskStatus" column="task_status" jdbcType="TINYINT"/>
<result property="remark" column="remark" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
</resultMap>
<!--查询单个-->
<select id="queryById" resultMap="SystemTaskMap">
select
task_id, bean_name, method_name, method_params, cron_expression, task_status, remark, create_time, update_time
from system_task
where task_id = #{taskId}
</select>
<!--新增所有列-->
<insert id="insert">
insert into system_task(bean_name, method_name, method_params, cron_expression, task_status, remark, create_time, update_time)
values (#{beanName}, #{methodName}, #{methodParams}, #{cronExpression}, #{taskStatus}, #{remark}, #{createTime}, #{updateTime})
</insert>
<!--通过主键修改数据-->
<update id="update">
update system_task
<set>
<if test="beanName != null and beanName != ''">
bean_name = #{beanName},
</if>
<if test="methodName != null and methodName != ''">
method_name = #{methodName},
</if>
<if test="methodParams != null and methodParams != ''">
method_params = #{methodParams},
</if>
<if test="cronExpression != null and cronExpression != ''">
cron_expression = #{cronExpression},
</if>
<if test="taskStatus != null">
task_status = #{taskStatus},
</if>
<if test="remark != null and remark != ''">
remark = #{remark},
</if>
<if test="createTime != null">
create_time = #{createTime},
</if>
<if test="updateTime != null">
update_time = #{updateTime},
</if>
</set>
where task_id = #{taskId}
</update>
<!--通过主键删除-->
<delete id="deleteById">
delete from system_task where task_id = #{taskId}
</delete>
<select id="selectTasksByStatus" resultMap="SystemTaskMap">
select
task_id, bean_name, method_name, method_params, cron_expression, task_status, remark, create_time, update_time
from system_task
where task_status = #{taskStatus}
</select>
</mapper>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
/**
* @描述 系统定时任务业务层
* @创建人 yhgh
* @创建时间 2022/8/26 15:43
*/
@Service
public class SystemTaskService {
@Autowired
private SystemTaskDao systemTaskDao;
@Autowired
private CronTaskRegistrar cronTaskRegistrar;
/**
* 新增系统定时任务
* @param systemTask
* @return
*/
public boolean addTask(SystemTask systemTask){
if (!StringUtils.hasText(systemTask.getBeanName()) ||
!StringUtils.hasText(systemTask.getMethodName()) ||
!StringUtils.hasText(systemTask.getCronExpression())){
return false;
}
systemTask.setTaskId(UUID.randomUUID().toString());
Date now = new Date();
systemTask.setCreateTime(now);
systemTask.setUpdateTime(now);
int insert = systemTaskDao.insert(systemTask);
if (insert <= 0) {
return false;
} else {
if (systemTask.getTaskStatus()) {
SchedulingRunnable task = new SchedulingRunnable(systemTask.getBeanName(), systemTask.getMethodName(), systemTask.getMethodParams());
cronTaskRegistrar.addCronTask(task, systemTask.getCronExpression());
}
}
return true;
}
/**
* 根据id更新系统定时任务
* @param systemTask
* @return
*/
public boolean updateTask(SystemTask systemTask){
SystemTask old = systemTaskDao.queryById(systemTask.getTaskId());
systemTask.setUpdateTime(new Date());
int update = systemTaskDao.update(systemTask);
if (update <= 0) {
return false;
}
// 删除老的定时任务
SchedulingRunnable task = new SchedulingRunnable(old.getBeanName(), old.getMethodName(), old.getMethodParams());
cronTaskRegistrar.removeCronTask(task);
// 如果新定时任务状态为正常,开启新定时任务
SystemTask newTask = systemTaskDao.queryById(systemTask.getTaskId());
if (newTask.getTaskStatus()){
SchedulingRunnable ta = new SchedulingRunnable(newTask.getBeanName(), newTask.getMethodName(), newTask.getMethodParams());
cronTaskRegistrar.addCronTask(ta, newTask.getCronExpression());
}
return true;
}
/**
* 根据id删除系统定时任务
* @param systemTask
* @return
*/
public boolean removeTask(SystemTask systemTask){
SystemTask ta = systemTaskDao.queryById(systemTask.getTaskId());
int delete = systemTaskDao.deleteById(systemTask.getTaskId());
if (delete <= 0)
return false;
else{
if (ta.getTaskStatus()) {
SchedulingRunnable task = new SchedulingRunnable(ta.getBeanName(), ta.getMethodName(), ta.getMethodParams());
cronTaskRegistrar.removeCronTask(task);
}
}
return true;
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @描述 项目启动完成后,加载数据库里状态为正常的定时任务
* @创建人 yhgh
* @创建时间 2022/8/26 15:22
*/
@Component
public class SystemTaskRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(SystemTaskRunner.class);
@Autowired
private SystemTaskDao systemTaskDao;
@Autowired
private CronTaskRegistrar cronTaskRegistrar;
@Override
public void run(String... args) {
// 初始加载数据库里状态为正常的定时任务
List<SystemTask> taskList = systemTaskDao.selectTasksByStatus(true);
if (CollectionUtils.isNotEmpty(taskList)) {
for (SystemTask task : taskList) {
SchedulingRunnable schedulingRunnable = new SchedulingRunnable(task.getBeanName(), task.getMethodName(), task.getMethodParams());
cronTaskRegistrar.addCronTask(schedulingRunnable, task.getCronExpression());
}
logger.info("定时任务已加载完毕...");
}
}
}
可以百度搜索cron表达式生成
Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义
第一位:Seconds(秒)--可出现", - * /"四个字符,有效范围为0-59的整数 第二位:Minutes(分)--可出现", - * /"四个字符,有效范围为0-59的整数 第三位:Hours(时)--可出现", - * /"四个字符,有效范围为0-23的整数 第四位:DayofMonth(日)--可出现", - * / ? L W C"八个字符,有效范围为0-31的整数 第五位:Month(月)--可出现", - * /"四个字符,有效范围为1-12的整数或JAN-DEc 第六位:DayofWeek(星期)--可出现", - * / ? L C #"四个字符,有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推 第七位:Year(年)--可出现", - * /"四个字符,有效范围为1970-2099年
注意事项:
每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:
(1)*:表示匹配该域的任意值。假如在Minutes域使用*, 即表示每分钟都会触发事件。
(2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
(3)-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
(4)/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
(5),:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
(6)L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
(7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
(8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
(9)#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。
常用表达式例子
(1)0 0 2 1 * ? * 表示在每月的1日的凌晨2点调整任务
(2)0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
(3)0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(4)0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
(5)0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
(6)0 0 12 ? * WED 表示每个星期三中午12点
(7)0 0 12 * * ? 每天中午12点触发
(8)0 15 10 ? * * 每天上午10:15触发
(9)0 15 10 * * ? 每天上午10:15触发
(10)0 15 10 * * ? * 每天上午10:15触发
(11)0 15 10 * * ? 2005 2005年的每天上午10:15触发
(12)0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
(13)0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
(14)0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(15)0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
(16)0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
(17)0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
(18)0 15 10 15 * ? 每月15日上午10:15触发
(19)0 15 10 L * ? 每月最后一日的上午10:15触发
(20)0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
(21)0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
(22)0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
传统的定时任务的缺点就是,如果进行横向扩展为多实例集群部署时,遇到了问题:定时任务在多个应用实例中重复执行了。此时quartz可以很好的解决分布式集群任务调度的问题,使得无论集群中有多少应用实例,定时任务只会触发一次。
Scheduler:与quartz schedule交互的主要api Job:Scheduler执行组件需要实现的接口(你要做什么事) JobDetail:用于定义实现了Job接口的实例 Trigger:用于执行给定作业的计划的组件(你什么时候去做) JobBuilder:用于构建JobDetail实例,或者说定义Job的实例 TriggerBuilder:用于构建触发器实例
Quartz
官方提供了11张数据表,这里使用mysql(innodb)的数据表,也有其他数据库的表,可以到官网(http://www.quartz-scheduler.org/downloads/)下载
1、建表
#
# 在Quartz属性文件中,需要设置
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
JOB_NAME VARCHAR(190) NOT NULL COMMENT '集群中job的名字',
JOB_GROUP VARCHAR(190) NOT NULL COMMENT '集群中job的所属组的名字',
DESCRIPTION VARCHAR(250) NULL COMMENT '详细描述信息',
JOB_CLASS_NAME VARCHAR(250) NOT NULL COMMENT '集群中个notejob实现类的全限定名,quartz就是根据这个路径到classpath找到该job类',
IS_DURABLE VARCHAR(1) NOT NULL COMMENT '是否持久化,把该属性设置为1,quartz会把job持久化到数据库中',
IS_NONCONCURRENT VARCHAR(1) NOT NULL COMMENT '是否并发执行',
IS_UPDATE_DATA VARCHAR(1) NOT NULL COMMENT '是否更新数据',
REQUESTS_RECOVERY VARCHAR(1) NOT NULL COMMENT '是否接受恢复执行,默认为false,设置了RequestsRecovery为true,则该job会被重新执行',
JOB_DATA BLOB NULL COMMENT '一个blob字段,存放持久化job对象',
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB COMMENT='已配置的jobDetail的详细信息';
CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
TRIGGER_NAME VARCHAR(190) NOT NULL COMMENT '触发器的名字',
TRIGGER_GROUP VARCHAR(190) NOT NULL COMMENT '触发器所属组的名字',
JOB_NAME VARCHAR(190) NOT NULL COMMENT 'qrtz_job_details表job_name的外键',
JOB_GROUP VARCHAR(190) NOT NULL COMMENT 'qrtz_job_details表job_group的外键',
DESCRIPTION VARCHAR(250) NULL COMMENT '详细描述信息',
NEXT_FIRE_TIME BIGINT(13) NULL COMMENT '上一次触发时间(毫秒)',
PREV_FIRE_TIME BIGINT(13) NULL COMMENT '下一次触发时间,默认为-1,意味不会自动触发',
PRIORITY INTEGER NULL COMMENT '优先级',
TRIGGER_STATE VARCHAR(16) NOT NULL COMMENT '当前触发器状态,设置为ACQUIRED,如果设置为WAITING,则job不会触发 ( WAITING:等待 PAUSED:暂停ACQUIRED:正常执行 BLOCKED:阻塞 ERROR:错误)',
TRIGGER_TYPE VARCHAR(8) NOT NULL COMMENT '触发器的类型,使用cron表达式',
START_TIME BIGINT(13) NOT NULL COMMENT '开始时间',
END_TIME BIGINT(13) NULL COMMENT '结束时间',
CALENDAR_NAME VARCHAR(190) NULL COMMENT '日程表名称,表qrtz_calendars的calendar_name字段外键',
MISFIRE_INSTR SMALLINT(2) NULL COMMENT '措施或者是补偿执行的策略',
JOB_DATA BLOB NULL COMMENT '一个blob字段,存放持久化job对象',
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB COMMENT='触发器的基本信息';
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
TRIGGER_NAME VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_ name的外键',
TRIGGER_GROUP VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
REPEAT_COUNT BIGINT(7) NOT NULL COMMENT '重复的次数统计',
REPEAT_INTERVAL BIGINT(12) NOT NULL COMMENT '重复的间隔时间',
TIMES_TRIGGERED BIGINT(10) NOT NULL COMMENT '已经触发的次数',
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB COMMENT='简单的 Trigger';
CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
TRIGGER_NAME VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
TRIGGER_GROUP VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
CRON_EXPRESSION VARCHAR(120) NOT NULL COMMENT 'cron表达式',
TIME_ZONE_ID VARCHAR(80) NULL COMMENT '时区',
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB COMMENT='触发器的cron表达式';
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
TRIGGER_NAME VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_ name的外键',
TRIGGER_GROUP VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
STR_PROP_1 VARCHAR(512) NULL COMMENT 'String类型的trigger的第一个参数',
STR_PROP_2 VARCHAR(512) NULL COMMENT 'String类型的trigger的第二个参数',
STR_PROP_3 VARCHAR(512) NULL COMMENT 'String类型的trigger的第三个参数',
INT_PROP_1 INT NULL COMMENT 'int类型的trigger的第一个参数',
INT_PROP_2 INT NULL COMMENT 'int类型的trigger的第二个参数',
LONG_PROP_1 BIGINT NULL COMMENT 'long类型的trigger的第一个参数',
LONG_PROP_2 BIGINT NULL COMMENT 'long类型的trigger的第二个参数',
DEC_PROP_1 NUMERIC(13,4) NULL COMMENT 'decimal类型的trigger的第一个参数',
DEC_PROP_2 NUMERIC(13,4) NULL COMMENT 'decimal类型的trigger的第二个参数',
BOOL_PROP_1 VARCHAR(1) NULL COMMENT 'Boolean类型的trigger的第一个参数',
BOOL_PROP_2 VARCHAR(1) NULL COMMENT 'Boolean类型的trigger的第二个参数',
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB COMMENT='存储CalendarIntervalTrigger和DailyTimeIntervalTrigger';
CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
TRIGGER_NAME VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
TRIGGER_GROUP VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
BLOB_DATA BLOB NULL COMMENT '一个blob字段,存放持久化Trigger对象',
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB COMMENT='Trigger作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)';
CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
CALENDAR_NAME VARCHAR(190) NOT NULL COMMENT '日历名称',
CALENDAR BLOB NOT NULL COMMENT '一个blob字段,存放持久化calendar对象',
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB COMMENT='以 Blob 类型存储存放日历信息,quartz可配置一个日历来指定一个时间范围';
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
TRIGGER_GROUP VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB COMMENT='存储已暂停的 Trigger 组的信息';
CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
ENTRY_ID VARCHAR(95) NOT NULL COMMENT '调度器实例id',
TRIGGER_NAME VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
TRIGGER_GROUP VARCHAR(190) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
INSTANCE_NAME VARCHAR(190) NOT NULL COMMENT '调度器实例名',
FIRED_TIME BIGINT(13) NOT NULL COMMENT '触发的时间',
SCHED_TIME BIGINT(13) NOT NULL COMMENT '定时器制定的时间',
PRIORITY INTEGER NOT NULL COMMENT '优先级',
STATE VARCHAR(16) NOT NULL COMMENT '状态',
JOB_NAME VARCHAR(190) NULL COMMENT '集群中job的名字',
JOB_GROUP VARCHAR(190) NULL COMMENT '集群中job的所属组的名字',
IS_NONCONCURRENT VARCHAR(1) NULL COMMENT '是否并发',
REQUESTS_RECOVERY VARCHAR(1) NULL COMMENT '是否接受恢复执行,默认为false,设置了RequestsRecovery为true,则会被重新执行',
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB COMMENT='存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息';
CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
INSTANCE_NAME VARCHAR(190) NOT NULL COMMENT '之前配置文件中org.quartz.scheduler.instanceId配置的名字,就会写入该字段',
LAST_CHECKIN_TIME BIGINT(13) NOT NULL COMMENT '上次检查时间',
CHECKIN_INTERVAL BIGINT(13) NOT NULL COMMENT '检查间隔时间',
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB COMMENT='存储集群中note实例信息,quartz会定时读取该表的信息判断集群中每个实例的当前状态';
CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL COMMENT '调度名称',
LOCK_NAME VARCHAR(40) NOT NULL COMMENT '悲观锁名称',
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB COMMENT='存储程序的悲观锁的信息(假如使用了悲观锁)';
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
commit;
2、项目中引入依赖
<!--springboot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--quartz依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
3、application.yml配置文件
server:
port: 18000
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/quartz-test?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=Asia/Shanghai
type: com.alibaba.druid.pool.DruidDataSource
#数据库连接池
druid:
# 初始化时建立物理连接的个数
initial-size: 10
# 最小连接池数量
min-idle: 5
# 最大连接池数量
max-active: 20
# 获取连接时最大等待时间,单位毫秒
max-wait: 60000
# 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
test-while-idle: true
# 既作为检测的间隔时间又作为testWhileIdel执行的依据
time-between-eviction-runs-millis: 60000
#销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
min-evictable-idle-time-millis: 30000
# 使用jdbc的方式持久化定时任务
quartz:
job-store-type: jdbc
4、TaskInfo实体类,为了传参方便
package top.ygang.quartztest.quartz;
import org.quartz.JobDataMap;
import java.util.Date;
/**
* @描述 任务信息
* @创建人 yhgh
*/
public class TaskInfo {
/**
* 任务名称
*/
private String jobName;
/**
* 任务组
*/
private String jobGroup;
/**
* 任务描述
*/
private String description;
/**
* Job实现类全类名
*/
private String className;
/**
* 触发器名称
*/
private String triggerName;
/**
* 触发器组
*/
private String triggerGroup;
/**
* cron表达式
*/
private String cron;
/**
* 创建时间
*/
private Date createTime;
/**
* execute的执行参数
*/
private JobDataMap jobDataMap;
/**
* 任务状态
*/
private String state;
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getTriggerName() {
return triggerName;
}
public void setTriggerName(String triggerName) {
this.triggerName = triggerName;
}
public String getTriggerGroup() {
return triggerGroup;
}
public void setTriggerGroup(String triggerGroup) {
this.triggerGroup = triggerGroup;
}
public String getCron() {
return cron;
}
public void setCron(String cron) {
this.cron = cron;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public JobDataMap getJobDataMap() {
return jobDataMap;
}
public void setJobDataMap(JobDataMap jobDataMap) {
this.jobDataMap = jobDataMap;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
5、业务层,处理各种关于定时任务的业务
package top.ygang.quartztest.quartz;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.*;
/**
* @描述 quartz业务层
* @创建人 yhgh
*/
@Service
public class QuartzService {
Logger logger = LoggerFactory.getLogger(QuartzService.class);
@Autowired
private Scheduler scheduler;
/**
* 获取所有任务列表
* @return
*/
public List<TaskInfo> getJobList() {
List<TaskInfo> list = new ArrayList<>();
try {
List<String> jobGroupNames = scheduler.getJobGroupNames();
for (String groupJob : jobGroupNames) {
for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(groupJob))) {
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
Trigger trigger = triggers.get(0);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
TriggerKey triggerKey = trigger.getKey();
String state = scheduler.getTriggerState(trigger.getKey()).name();
String jName = jobKey.getName();
String jGroup = jobKey.getGroup();
String tGroup = triggerKey.getGroup();
String tName = triggerKey.getName();
CronTrigger cronTrigger = (CronTrigger) trigger;
String cron = cronTrigger.getCronExpression();
String description = jobDetail.getDescription();
String className = jobDetail.getJobClass().getName();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
Date createTime = (Date) jobDataMap.get("createTime");
jobDataMap.remove("createTime");
TaskInfo info = new TaskInfo();
info.setJobName(jName);
info.setJobGroup(jGroup);
info.setClassName(className);
info.setDescription(description);
info.setCron(cron);
info.setTriggerName(tName);
info.setTriggerGroup(tGroup);
info.setCreateTime(createTime);
info.setJobDataMap(jobDataMap);
info.setState(state);
list.add(info);
}
}
}catch (Exception e){
logger.error("获取任务列表失败",e);
return list;
}
return list;
}
/**
* 新增定时任务
*
* @param taskInfo
*/
public void addJob(TaskInfo taskInfo) {
try {
// 根据传入的类名加载Job实现类
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(taskInfo.getClassName());
// 将创建时间放到参数中保存
taskInfo.getJobDataMap().put("createTime",new Date());
// 构建JobDetail
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(taskInfo.getJobName(), taskInfo.getJobGroup())
.withDescription(taskInfo.getDescription())
.usingJobData(taskInfo.getJobDataMap())
.build();
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger()
// 此处默认使用任务名称、组名作为触发器名,也可以自定义
.withIdentity(taskInfo.getJobName(), taskInfo.getJobGroup())
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(taskInfo.getCron()))
.build();
// 启动调度器
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
} catch (Exception e) {
logger.error("创建定时任务失败",e);
}
}
/**
* 暂停定时任务
* @param taskInfo
* @throws SchedulerException
*/
public void pauseJob(TaskInfo taskInfo) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(taskInfo.getJobName(), taskInfo.getJobGroup()));
}
/**
* 开始定时任务
* @param taskInfo
* @throws SchedulerException
*/
public void resumeJob(TaskInfo taskInfo) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(taskInfo.getJobName(), taskInfo.getJobGroup()));
}
/**
* 更新任务
* 注意:只能用来更新cron
* @param taskInfo
* @throws SchedulerException
*/
public void rescheduleJob(TaskInfo taskInfo) throws SchedulerException {
String jobName = taskInfo.getJobName();
String jobGroup = taskInfo.getJobGroup();
String description = taskInfo.getDescription();
String cron = taskInfo.getCron();
JobDataMap jobDataMap = taskInfo.getJobDataMap();
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
JobKey jobKey = new JobKey(jobName, jobGroup);
Trigger trigger = scheduler.getTrigger(triggerKey);
// 如果修改cron
if (StringUtils.hasText(cron)){
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
.cronSchedule(cron)
.withMisfireHandlingInstructionDoNothing();
trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.withSchedule(cronScheduleBuilder).build();
}
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
JobBuilder jobBuilder = jobDetail.getJobBuilder();
// 如果修改描述
if (StringUtils.hasText(description)){
jobBuilder = jobBuilder.withDescription(description);
}
// 如果修改参数
if (jobDataMap != null && jobDataMap.size() > 0){
Date createTime = (Date) jobDetail.getJobDataMap().get("createTime");
jobDataMap.put("createTime",createTime);
jobBuilder = jobBuilder.usingJobData(jobDataMap);
}
jobDetail = jobBuilder.build();
Set<Trigger> triggerSet = new HashSet<>();
triggerSet.add(trigger);
scheduler.scheduleJob(jobDetail, triggerSet,true);
}
/**
* 删除定时任务
* @param taskInfo
* @throws SchedulerException
*/
public void deleteJob(TaskInfo taskInfo) throws SchedulerException {
scheduler.pauseTrigger(TriggerKey.triggerKey(taskInfo.getJobName(), taskInfo.getJobGroup()));
scheduler.unscheduleJob(TriggerKey.triggerKey(taskInfo.getJobName(), taskInfo.getJobGroup()));
scheduler.deleteJob(JobKey.jobKey(taskInfo.getJobName(), taskInfo.getJobGroup()));
}
}
6、控制层
package top.ygang.quartztest.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import top.ygang.quartztest.quartz.QuartzService;
import top.ygang.quartztest.quartz.TaskInfo;
import java.util.List;
/**
* @描述
* @创建人 yhgh
*/
@RestController
public class QuartzController {
@Autowired
private QuartzService quartzService;
/**
* 新增定时任务
* @param taskInfo
* @return
*/
@PostMapping("/addJob")
public String addJob(@RequestBody TaskInfo taskInfo){
try{
quartzService.addJob(taskInfo);
return "success";
}catch (Exception e){
e.printStackTrace();
return "failed";
}
}
/**
* 删除定时任务
* @param taskInfo
* @return
*/
@PostMapping("/deleteJob")
public String deleteJob(@RequestBody TaskInfo taskInfo){
try{
quartzService.deleteJob(taskInfo);
return "success";
}catch (Exception e){
e.printStackTrace();
return "failed";
}
}
/**
* 更新定时任务
* @param taskInfo
* @return
*/
@PostMapping("/rescheduleJob")
public String rescheduleJob(@RequestBody TaskInfo taskInfo){
try{
quartzService.rescheduleJob(taskInfo);
return "success";
}catch (Exception e){
e.printStackTrace();
return "failed";
}
}
/**
* 暂停定时任务
* @param taskInfo
* @return
*/
@PostMapping("/pauseJob")
public String pauseJob(@RequestBody TaskInfo taskInfo){
try{
quartzService.pauseJob(taskInfo);
return "success";
}catch (Exception e){
e.printStackTrace();
return "failed";
}
}
/**
* 开始定时任务
* @param taskInfo
* @return
*/
@PostMapping("/resumeJob")
public String resumeJob(@RequestBody TaskInfo taskInfo){
try{
quartzService.resumeJob(taskInfo);
return "success";
}catch (Exception e){
e.printStackTrace();
return "failed";
}
}
/**
* 查询定时任务列表
* @return
*/
@PostMapping("/getJobList")
public List<TaskInfo> getJobList(){
try{
List<TaskInfo> jobList = quartzService.getJobList();
return jobList;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
}
7、定义一个定时任务
package top.ygang.quartztest.quartz.task;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* @描述
* @创建人 yhgh
*/
public class TestTask implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
String msg = (String) jobDataMap.get("msg");
System.out.println("执行定时任务 : " + msg);
}
}