SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见。
程序员每天的CV 与 板砖,也要知其所以然,本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCloud 微服务系列项目开发
Quartz是由Java语言编写,是OpenSymphony开源组织在Job scheduling领域的项目。

首先是在项目的 pom.xml 文件中添加依赖如下
org.springframework.boot spring-boot-starter-quartz 2.7.9 com.google.code.gson gson
然后添加了下定时任务的配置信息
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;import javax.sql.DataSource;
import java.util.Properties;/*** 定时任务配置** @author 早起的年轻人* @since 2.0.0 2023-04-20*/
@Configuration
public class ScheduleConfig {@Beanpublic SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {SchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setDataSource(dataSource);//quartz参数Properties prop = new Properties();//#调度器实例名称prop.put("org.quartz.scheduler.instanceName", "RenrenScheduler");//#调度器实例编号自动生成prop.put("org.quartz.scheduler.instanceId", "AUTO");//线程池配置prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");prop.put("org.quartz.threadPool.threadCount", "20");prop.put("org.quartz.threadPool.threadPriority", "5");//JobStore配置prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");//集群配置 开启分布式部署prop.put("org.quartz.jobStore.isClustered", "true");prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");prop.put("org.quartz.jobStore.misfireThreshold", "12000");prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");//PostgreSQL数据库,需要打开此注释//prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
// prop.put(" org.quartz.jobStore.driverDelegateClass "," org.quartz.impl.jdbcjobstore.StdJDBCDelegate");factory.setQuartzProperties(prop);factory.setSchedulerName("RenrenScheduler");//延时启动factory.setStartupDelay(10);factory.setApplicationContextSchedulerContextKey("applicationContextKey");//可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了factory.setOverwriteExistingJobs(true);//设置自动启动,默认为truefactory.setAutoStartup(true);return factory;}
}
然后添加 Quartz 所需要的表结构
/*Navicat Premium Data TransferSource Server : mac-docker-1Source Server Type : MySQLSource Server Version : 50725Source Host : 127.0.0.1:3306Source Schema : spring_bootTarget Server Type : MySQLTarget Server Version : 50725File Encoding : 65001Date: 19/03/2023 15:00:20
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for QRTZ_BLOB_TRIGGERS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`;
CREATE TABLE `QRTZ_BLOB_TRIGGERS` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`BLOB_DATA` blob,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),CONSTRAINT `QRTZ_BLOB_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_CALENDARS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_CALENDARS`;
CREATE TABLE `QRTZ_CALENDARS` (`SCHED_NAME` varchar(120) NOT NULL,`CALENDAR_NAME` varchar(200) NOT NULL,`CALENDAR` blob NOT NULL,PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_CRON_TRIGGERS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_CRON_TRIGGERS`;
CREATE TABLE `QRTZ_CRON_TRIGGERS` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`CRON_EXPRESSION` varchar(200) NOT NULL,`TIME_ZONE_ID` varchar(80) DEFAULT NULL,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),CONSTRAINT `QRTZ_CRON_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_FIRED_TRIGGERS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_FIRED_TRIGGERS`;
CREATE TABLE `QRTZ_FIRED_TRIGGERS` (`SCHED_NAME` varchar(120) NOT NULL,`ENTRY_ID` varchar(95) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`INSTANCE_NAME` varchar(200) NOT NULL,`FIRED_TIME` bigint(13) NOT NULL,`SCHED_TIME` bigint(13) NOT NULL,`PRIORITY` int(11) NOT NULL,`STATE` varchar(16) NOT NULL,`JOB_NAME` varchar(200) DEFAULT NULL,`JOB_GROUP` varchar(200) DEFAULT NULL,`IS_NONCONCURRENT` varchar(1) DEFAULT NULL,`REQUESTS_RECOVERY` varchar(1) DEFAULT NULL,PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_JOB_DETAILS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_JOB_DETAILS`;
CREATE TABLE `QRTZ_JOB_DETAILS` (`SCHED_NAME` varchar(120) NOT NULL,`JOB_NAME` varchar(200) NOT NULL,`JOB_GROUP` varchar(200) NOT NULL,`DESCRIPTION` varchar(250) DEFAULT NULL,`JOB_CLASS_NAME` varchar(250) NOT NULL,`IS_DURABLE` varchar(1) NOT NULL,`IS_NONCONCURRENT` varchar(1) NOT NULL,`IS_UPDATE_DATA` varchar(1) NOT NULL,`REQUESTS_RECOVERY` varchar(1) NOT NULL,`JOB_DATA` blob,PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_LOCKS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_LOCKS`;
CREATE TABLE `QRTZ_LOCKS` (`SCHED_NAME` varchar(120) NOT NULL,`LOCK_NAME` varchar(40) NOT NULL,PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_PAUSED_TRIGGER_GRPS`;
CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_SCHEDULER_STATE
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`;
CREATE TABLE `QRTZ_SCHEDULER_STATE` (`SCHED_NAME` varchar(120) NOT NULL,`INSTANCE_NAME` varchar(200) NOT NULL,`LAST_CHECKIN_TIME` bigint(13) NOT NULL,`CHECKIN_INTERVAL` bigint(13) NOT NULL,PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_SIMPLE_TRIGGERS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_SIMPLE_TRIGGERS`;
CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`REPEAT_COUNT` bigint(7) NOT NULL,`REPEAT_INTERVAL` bigint(12) NOT NULL,`TIMES_TRIGGERED` bigint(10) NOT NULL,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),CONSTRAINT `QRTZ_SIMPLE_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_SIMPROP_TRIGGERS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_SIMPROP_TRIGGERS`;
CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`STR_PROP_1` varchar(512) DEFAULT NULL,`STR_PROP_2` varchar(512) DEFAULT NULL,`STR_PROP_3` varchar(512) DEFAULT NULL,`INT_PROP_1` int(11) DEFAULT NULL,`INT_PROP_2` int(11) DEFAULT NULL,`LONG_PROP_1` bigint(20) DEFAULT NULL,`LONG_PROP_2` bigint(20) DEFAULT NULL,`DEC_PROP_1` decimal(13,4) DEFAULT NULL,`DEC_PROP_2` decimal(13,4) DEFAULT NULL,`BOOL_PROP_1` varchar(1) DEFAULT NULL,`BOOL_PROP_2` varchar(1) DEFAULT NULL,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for QRTZ_TRIGGERS
-- ----------------------------
DROP TABLE IF EXISTS `QRTZ_TRIGGERS`;
CREATE TABLE `QRTZ_TRIGGERS` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`JOB_NAME` varchar(200) NOT NULL,`JOB_GROUP` varchar(200) NOT NULL,`DESCRIPTION` varchar(250) DEFAULT NULL,`NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,`PREV_FIRE_TIME` bigint(13) DEFAULT NULL,`PRIORITY` int(11) DEFAULT NULL,`TRIGGER_STATE` varchar(16) NOT NULL,`TRIGGER_TYPE` varchar(8) NOT NULL,`START_TIME` bigint(13) NOT NULL,`END_TIME` bigint(13) DEFAULT NULL,`CALENDAR_NAME` varchar(200) DEFAULT NULL,`MISFIRE_INSTR` smallint(2) DEFAULT NULL,`JOB_DATA` blob,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),KEY `SCHED_NAME` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),CONSTRAINT `QRTZ_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;SET FOREIGN_KEY_CHECKS = 1;
本文章接 SpringBoot ElasticSearch 实现订单的分页查询 【SpringBoot系列17】
ScheduleJobService.java
public interface ScheduleJobService extends IService {/** 保存定时任务*/boolean newObj(ScheduleJobEntity scheduleJob);/**更新定时任务*/void update(ScheduleJobEntity scheduleJob);
}
ScheduleJobServiceImpl.java 实现类
@Service("scheduleJobService")
public class ScheduleJobServiceImpl extends ServiceImpl implements ScheduleJobService {@Resourceprivate Scheduler scheduler;/*** 项目启动时,初始化定时器*/@PostConstructpublic void init() {//查询当前所有的定时任务List scheduleJobList = this.list(new QueryWrapper<>());try {scheduler.clear();} catch (SchedulerException e) {e.printStackTrace();}for (ScheduleJobEntity scheduleJob : scheduleJobList) {//获取任务的表达式触发器CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getJobId());//如果不存在,则创建if (cronTrigger == null) {ScheduleUtils.createScheduleJob(scheduler, scheduleJob);} else {ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);}}}
}
新建定时任务与更新定时任务如下:
@Override@Transactional(rollbackFor = Exception.class)public boolean newObj(ScheduleJobEntity scheduleJob) {scheduleJob.setCreateTime(new Date());//设置状态 默认是启动scheduleJob.setStatus(Constant.ScheduleStatus.NORMAL.getValue());//cron表达式String cronExpression = scheduleJob.getCronExpression();//验证boolean valid = CronExpression.isValidExpression(cronExpression);if(!valid){throw new RuntimeException("cron 表达式不正确");}//保存任务this.save(scheduleJob);//构建job信息ScheduleUtils.createScheduleJob(scheduler, scheduleJob);return false;}@Override@Transactional(rollbackFor = Exception.class)public void update(ScheduleJobEntity scheduleJob) {ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);//更新数据库this.updateById(scheduleJob);}
ScheduleJobEntity.java 类
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.util.Date;/*** 定时任务*/
@TableName("schedule_job")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ScheduleJobEntity implements Serializable {private static final long serialVersionUID = 1L;/*** 任务调度参数key*/public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";/*** 任务id*/@TableIdprivate Long jobId;/*** spring bean名称*/private String beanName;/*** 方法名*/private String methodName;/*** 参数*/private String params;/*** cron表达式*/private String cronExpression;/*** 任务状态*/private Integer status;/*** 备注*/private String remark;/*** 创建时间*/private Date createTime;}
/*** 定时任务工具类** @author 早起的年轻人* @since 1.2.0 2022-11-28*/
public class ScheduleUtils {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) {throw new RuntimeException("获取定时任务CronTrigger出现异常", e);}}/*** 创建定时任务*/public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {try {JobKey jobKey = getJobKey(scheduleJob.getJobId());//构建job信息JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(jobKey).build();//表达式调度构建器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()).withMisfireHandlingInstructionDoNothing();//按新的cronExpression表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder).build();Gson gson = new Gson();//放入参数,运行时的方法可以获取jobDetail.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, gson.toJson(scheduleJob));scheduler.scheduleJob(jobDetail, trigger);//暂停任务if(scheduleJob.getStatus() == Constant.ScheduleStatus.PAUSE.getValue()){pauseJob(scheduler, scheduleJob.getJobId());}} catch (SchedulerException e) {throw new RuntimeException("创建定时任务失败 ", e);}}/*** 更新定时任务*/public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {try {TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId());//表达式调度构建器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()).withMisfireHandlingInstructionDoNothing();CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId());//按新的cronExpression表达式重新构建triggertrigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();Gson gson = new Gson();//参数trigger.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, gson.toJson(scheduleJob));scheduler.rescheduleJob(triggerKey, trigger);//暂停任务if(scheduleJob.getStatus() == Constant.ScheduleStatus.PAUSE.getValue()){pauseJob(scheduler, scheduleJob.getJobId());}} catch (SchedulerException e) {throw new RuntimeException("更新定时任务失败", e);}}/*** 立即执行任务*/public static void run(Scheduler scheduler, ScheduleJobEntity scheduleJob) {try {//参数JobDataMap dataMap = new JobDataMap();Gson gson = new Gson();dataMap.put(ScheduleJobEntity.JOB_PARAM_KEY,gson.toJson(scheduleJob));scheduler.triggerJob(getJobKey(scheduleJob.getJobId()), dataMap);} catch (SchedulerException e) {throw new RuntimeException("立即执行定时任务失败 "+e.getMessage(), e);}}/*** 暂停任务*/public static void pauseJob(Scheduler scheduler, Long jobId) {try {scheduler.pauseJob(getJobKey(jobId));} catch (SchedulerException e) {throw new RuntimeException("暂停定时任务失败", e);}}/*** 恢复任务*/public static void resumeJob(Scheduler scheduler, Long jobId) {try {scheduler.resumeJob(getJobKey(jobId));} catch (SchedulerException e) {throw new RuntimeException("暂停定时任务失败", e);}}/*** 删除定时任务*/public static void deleteScheduleJob(Scheduler scheduler, Long jobId) {try {scheduler.deleteJob(getJobKey(jobId));} catch (SchedulerException e) {throw new RuntimeException("删除定时任务失败", e);}}
}
项目源码在这里 :https://gitee.com/android.long/spring-boot-study/tree/master/biglead-api-13-quartz
有兴趣可以关注一下公众号:biglead