springBoot集成Quartz实现任务调度

quartz是一个很强大的任务调度插件,上一节已经讲述了springBoot自带的任务调度功能,但是只能满足简单的需求,集成quartz是为了满足更复杂的需求,比如需要执行的任务存到数据库中保存,包括配置任务信息触发器信息等,再比如需要对执行的任务随时暂停,删除,修改执行频率,执行参数等,而且也要随时添加新的任务去执行,这种复杂的需求下,简单的线程池或者定时任务就很难满足需求,所以就需要quartz来方便我们的使用。

虽然quartz很强大感觉很复杂,但是使用起来其实很简单的。

quartz表结构如下,mysql的数据库

create table if not exists apg.QRTZ_CALENDARS
(
 SCHED_NAME varchar(120) not null,
 CALENDAR_NAME varchar(200) not null,
 CALENDAR blob not null,
 primary key (SCHED_NAME, CALENDAR_NAME)
);
create table if not exists apg.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 not null,
 STATE varchar(16) not null,
 JOB_NAME varchar(200) null,
 JOB_GROUP varchar(200) null,
 IS_NONCONCURRENT varchar(1) null,
 REQUESTS_RECOVERY varchar(1) null,
 primary key (SCHED_NAME, ENTRY_ID)
);
create index IDX_QRTZ_FT_INST_JOB_REQ_RCVRY
 on apg.QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
create index IDX_QRTZ_FT_JG
 on apg.QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
create index IDX_QRTZ_FT_J_G
 on apg.QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
create index IDX_QRTZ_FT_TG
 on apg.QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
create index IDX_QRTZ_FT_TRIG_INST_NAME
 on apg.QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
create index IDX_QRTZ_FT_T_G
 on apg.QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
create table if not exists apg.QRTZ_JOB_DETAILS
(
 SCHED_NAME varchar(120) not null,
 JOB_NAME varchar(200) not null,
 JOB_GROUP varchar(200) not null,
 DESCRIPTION varchar(250) 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 null,
 primary key (SCHED_NAME, JOB_NAME, JOB_GROUP)
);
create index IDX_QRTZ_J_GRP
 on apg.QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);
create index IDX_QRTZ_J_REQ_RECOVERY
 on apg.QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);
create table if not exists apg.QRTZ_LOCKS
(
 SCHED_NAME varchar(120) not null,
 LOCK_NAME varchar(40) not null,
 primary key (SCHED_NAME, LOCK_NAME)
);
create table if not exists apg.QRTZ_PAUSED_TRIGGER_GRPS
(
 SCHED_NAME varchar(120) not null,
 TRIGGER_GROUP varchar(200) not null,
 primary key (SCHED_NAME, TRIGGER_GROUP)
);
create table if not exists apg.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)
);
create table if not exists apg.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) null,
 NEXT_FIRE_TIME bigint(13) null,
 PREV_FIRE_TIME bigint(13) null,
 PRIORITY int null,
 TRIGGER_STATE varchar(16) not null,
 TRIGGER_TYPE varchar(8) not null,
 START_TIME bigint(13) not null,
 END_TIME bigint(13) null,
 CALENDAR_NAME varchar(200) null,
 MISFIRE_INSTR smallint(2) null,
 JOB_DATA blob null,
 primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
 constraint QRTZ_TRIGGERS_ibfk_1
 foreign key (SCHED_NAME, JOB_NAME, JOB_GROUP) references apg.QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)
);
create table if not exists apg.QRTZ_BLOB_TRIGGERS
(
 SCHED_NAME varchar(120) not null,
 TRIGGER_NAME varchar(200) not null,
 TRIGGER_GROUP varchar(200) not null,
 BLOB_DATA blob null,
 primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
 constraint QRTZ_BLOB_TRIGGERS_ibfk_1
 foreign key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP) references apg.QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
);
create index SCHED_NAME
 on apg.QRTZ_BLOB_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
create table if not exists apg.QRTZ_CRON_TRIGGERS
(
 SCHED_NAME varchar(120) not null,
 TRIGGER_NAME varchar(200) not null,
 TRIGGER_GROUP varchar(200) not null,
 CRON_EXPRESSION varchar(120) not null,
 TIME_ZONE_ID varchar(80) null,
 primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
 constraint QRTZ_CRON_TRIGGERS_ibfk_1
 foreign key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP) references apg.QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
);
create table if not exists apg.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 apg.QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
);
create table if not exists apg.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) null,
 STR_PROP_2 varchar(512) null,
 STR_PROP_3 varchar(512) null,
 INT_PROP_1 int null,
 INT_PROP_2 int null,
 LONG_PROP_1 bigint null,
 LONG_PROP_2 bigint null,
 DEC_PROP_1 decimal(13,4) null,
 DEC_PROP_2 decimal(13,4) null,
 BOOL_PROP_1 varchar(1) null,
 BOOL_PROP_2 varchar(1) null,
 primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
 constraint QRTZ_SIMPROP_TRIGGERS_ibfk_1
 foreign key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP) references apg.QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
);
create index IDX_QRTZ_T_C
 on apg.QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
create index IDX_QRTZ_T_G
 on apg.QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
create index IDX_QRTZ_T_J
 on apg.QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
create index IDX_QRTZ_T_JG
 on apg.QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);
create index IDX_QRTZ_T_NEXT_FIRE_TIME
 on apg.QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
create index IDX_QRTZ_T_NFT_MISFIRE
 on apg.QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);
create index IDX_QRTZ_T_NFT_ST
 on apg.QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
create index IDX_QRTZ_T_NFT_ST_MISFIRE
 on apg.QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
create index IDX_QRTZ_T_NFT_ST_MISFIRE_GRP
 on apg.QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);
create index IDX_QRTZ_T_N_G_STATE
 on apg.QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
create index IDX_QRTZ_T_N_STATE
 on apg.QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
create index IDX_QRTZ_T_STATE
 on apg.QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);

1、在pom中添加quartz的依赖

 

 org.springframework.boot
 spring-boot-starter-quartz

2、在项目中创建一个util包,并编写一个任务调度关联工具类,对job增删改查等操作

package com.apgblogs.springbootstudy.util;
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.Component;
import java.util.*;
/**
 * @author xiaomianyang
 * @description
 * @date 2019-07-17 16:24
 */
@Component
public class QuartzJobUtil {
 private static final Logger logger = LoggerFactory.getLogger(QuartzJobUtil.class);
 private static QuartzJobUtil quartzJobUtil;
 @Autowired
 private Scheduler scheduler;
 
 public QuartzJobUtil() {
 logger.info("init jobUtil");
 quartzJobUtil = this;
 }
 public static QuartzJobUtil getInstance() {
 logger.info("return JobCreateUtil");
 return QuartzJobUtil.quartzJobUtil;
 }
 /**
 * @description 创建job
 * @author xiaomianyang
 * @date 2019-07-17 17:31
 * @param [clazz, jobName, jobGroupName, cronExpression]
 * @return void
 */
 public void addJob(Class clazz, String jobName, String jobGroupName, String cronExpression) {
 addJob(clazz, jobName, jobGroupName, cronExpression, null);
 }
 /**
 * @description 创建job
 * @author xiaomianyang
 * @date 2019-07-17 17:31
 * @param [clazz, jobName, jobGroupName, cronExpression, argMap]
 * @return void
 */
 public void addJob(Class clazz, String jobName, String jobGroupName, String cronExpression, Map argMap) {
 try {
 // 启动调度器
 scheduler.start();
 //构建job信息
 JobDetail jobDetail = JobBuilder.newJob(((Job) clazz.newInstance()).getClass()).withIdentity(jobName, jobGroupName).build();
 //表达式调度构建器(即任务执行的时间)
 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
 //按新的cronExpression表达式构建一个新的trigger
 CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName).withSchedule(scheduleBuilder).build();
 //获得JobDataMap,写入数据
 if (argMap != null) {
 trigger.getJobDataMap().putAll(argMap);
 }
 scheduler.scheduleJob(jobDetail, trigger);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 /**
 * @description 暂停job
 * @author xiaomianyang
 * @date 2019-07-17 17:31
 * @param [jobName, jobGroupName]
 * @return void
 */
 public void pauseJob(String jobName, String jobGroupName) {
 try {
 scheduler.pauseJob(JobKey.jobKey(jobName, jobGroupName));
 } catch (SchedulerException e) {
 e.printStackTrace();
 }
 }
 /**
 * @description 恢复job
 * @author xiaomianyang
 * @date 2019-07-17 17:31
 * @param [jobName, jobGroupName]
 * @return void
 */
 public void resumeJob(String jobName, String jobGroupName) {
 try {
 scheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName));
 } catch (SchedulerException e) {
 e.printStackTrace();
 }
 }
 /**
 * @description 更新job频率
 * @author xiaomianyang
 * @date 2019-07-17 17:31
 * @param [jobName, jobGroupName, cronExpression]
 * @return void
 */
 public void updateJob(String jobName, String jobGroupName, String cronExpression) {
 updateJob(jobName, jobGroupName, cronExpression, null);
 }
 /**
 * @description 更新job频率和参数
 * @author xiaomianyang
 * @date 2019-07-17 17:31
 * @param [jobName, jobGroupName, cronExpression, argMap]
 * @return void
 */
 public void updateJob(String jobName, String jobGroupName, String cronExpression, Map argMap) {
 try {
 TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
 // 表达式调度构建器
 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
 CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
 // 按新的cronExpression表达式重新构建trigger
 trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
 //修改map
 if (argMap != null) {
 trigger.getJobDataMap().putAll(argMap);
 }
 // 按新的trigger重新设置job执行
 scheduler.rescheduleJob(triggerKey, trigger);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 /**
 * @description 更新job参数
 * @author xiaomianyang
 * @date 2019-07-17 17:30
 * @param [jobName, jobGroupName, argMap]
 * @return void
 */
 public void updateJob(String jobName, String jobGroupName, Map argMap) {
 try {
 TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
 CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
 //修改map
 trigger.getJobDataMap().putAll(argMap);
 // 按新的trigger重新设置job执行
 scheduler.rescheduleJob(triggerKey, trigger);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 /**
 * @description 删除job
 * @author xiaomianyang
 * @date 2019-07-17 17:30
 * @param [jobName, jobGroupName]
 * @return void
 */
 public void deleteJob(String jobName, String jobGroupName) {
 try {
 scheduler.pauseTrigger(TriggerKey.triggerKey(jobName, jobGroupName));
 scheduler.unscheduleJob(TriggerKey.triggerKey(jobName, jobGroupName));
 scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 /**
 * @description 启动所有定时任务
 * @author xiaomianyang
 * @date 2019-07-17 17:30
 * @param []
 * @return void
 */
 public void startAllJobs() {
 try {
 scheduler.start();
 } catch (Exception e) {
 throw new RuntimeException(e);
 }
 }
 /**
 * @description 关闭所有定时任务
 * @author xiaomianyang
 * @date 2019-07-17 17:30
 * @param []
 * @return void
 */
 public void shutdownAllJobs() {
 try {
 if (!scheduler.isShutdown()) {
 scheduler.shutdown();
 }
 } catch (Exception e) {
 throw new RuntimeException(e);
 }
 }
 /**
 * @description 获取所有任务列表
 * @author xiaomianyang
 * @date 2019-07-17 17:30
 * @param []
 * @return java.util.List>
 */
 public List> getAllJob() {
 GroupMatcher matcher = GroupMatcher.anyJobGroup();
 List> jobList = new ArrayList<>();
 Set jobKeys = null;
 try {
 jobKeys = scheduler.getJobKeys(matcher);
 for (JobKey jobKey : jobKeys) {
 List extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
 for (Trigger trigger : triggers) {
 Map job = new HashMap<>();
 job.put("jobName", jobKey.getName());
 job.put("jobGroupName", jobKey.getGroup());
 job.put("trigger", trigger.getKey());
 Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
 job.put("jobStatus", triggerState.name());
 if (trigger instanceof CronTrigger) {
 CronTrigger cronTrigger = (CronTrigger) trigger;
 String cronExpression = cronTrigger.getCronExpression();
 job.put("cronExpression", cronExpression);
 }
 jobList.add(job);
 }
 }
 } catch (SchedulerException e) {
 e.printStackTrace();
 }
 return jobList;
 }
}

3、在项目中创建一个task包,用来编写需要执行的任务类

package com.apgblogs.springbootstudy.task;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * @author xiaomianyang
 * @description
 * @date 2019-07-16 16:07
 */
public class TaskOne extends QuartzJobBean {
 private final Logger logger= LoggerFactory.getLogger(TaskOne.class);
 @Override
 protected void executeInternal(JobExecutionContext jobExecutionContext) {
 SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 logger.info("任务1执行:{}",simpleDateFormat.format(new Date()));
 }
}

4、在配置文件中修改quartz的存储类型为jdbc,默认是内存存储

......
quartz:
 job-store-type: jdbc
......

5、编写测试用例

由于测试用例直接就跑完了,所以休眠个一段时间,就可以看到任务输出了,每秒输出一次,这里的先进行了删除,如果任务已经有了就可以删除重新添加,跟数据库是同步的,实时修改和创建任务数据

@Test
public void addJob() throws Exception{
 quartzJobUtil.deleteJob("我的job","task");
 quartzJobUtil.addJob(TaskOne.class,"我的job","task","* * * * * ?");
 Thread.sleep(100000);
}
@Test
public void pauseJob(){
 quartzJobUtil.pauseJob("我的job","task");
}

6、可以启动测试看看结果

springBoot集成Quartz实现任务调度

测试结果

7、文章源码地址

关注+转发后私信我源码地址,感谢支持

quartz就已经集成上去了,有任何需要定时执行或者由用户手动创建添加的任务都可以用quartz实现,采用的数据库存储,对于已经添加好的job也就不用在重新添加了,只要项目每次启动就会根据定时计划继续执行,对jobDetail表映射实体类,也可以用jpa去查询任务信息,是不是很方便呢。


分享到:


相關文章: