一、quartz介绍
1.quartz是一个任务调度框架。
2.优点:
(1)支持多种类型的触发器(如简单触发器、cron触发器等)。
(2)支持作业和触发器的持久化(保存到数据库中)。
(3)支持分布式和集群模式。
3.核心概念:
(1)Trigger(触发器)
设置Job调度的时间触发规则。
(2)Job(任务)和JobDetail
Job:实现Job接口,在execute方法中编写具体业务逻辑。
JobDetail:用来存储Job实例的信息,调度器需要借助JobDetail对象添加Job实例。
(3)Scheduler(调度器)
任务调度容器,Trigger和Job需要加入到Scheduler中才能使用。
二、quartz应用
1、pom文件引用依赖
<!--quart任务调度依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2、建表(持久化准备)
在这个地方可以找到sql文件。
3、添加配置文件
spring:
quartz:
job-store-type: jdbc #将任务保存到数据库
wait-for-jobs-to-complete-on-shutdown: true #程序结束时会等待quartz相关内容结束
overwrite-existing-jobs: true #启动时更新已存在的job
jdbc:
initialize-schema: never #不初始化数据库
properties:
org:
quartz:
scheduler:
instanceName: scheduler #实例名
instanceId: AUTO #实例编号自动生成
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX #数据保存方式为数据库持久化
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #数据库代理类
tablePrefix: QRTZ_ #数据表的前缀
isClustered: false #是否以集群方式运行
clusterCheckinInterval: 10000 #调度实例失效的检查时间间隔,单位毫秒
useProperties: true #JobDataMaps是否都为String类型
misfireThreshold: 60000 #最大能忍受的触发超时时间
threadPool:
class: org.quartz.simpl.SimpleThreadPool #连接池实现类
threadCount: 10 #线程数量
threadPriority: 5 #线程优先级
threadsInheritContextClassLoaderOfInitializingThread: true #配置是否启动自动加载数据库内的定时任务,默认true
4、创建定时任务配置类
需要手动注入Bean。
package com.feng.config;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
/**
* 定时任务配置类
*
* @Author: feng
*/
@Configuration
public class ScheduleConfig {
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
@Bean(name = "scheduler")
public Scheduler scheduler() {
return schedulerFactoryBean.getScheduler();
}
}
5、创建实体类
package com.feng.pojo;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.quartz.JobDataMap;
/**
* quartz任务请求参数
*
* @Author: feng
* @DateTime: 2023/11/16 20:31
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QuartzParam {
@ApiModelProperty(value = "任务路径")
private String jobClassName;
@ApiModelProperty(value = "任务名称")
private String jobName;
@ApiModelProperty(value = "任务组名")
private String jobGroup;
@ApiModelProperty(value = "任务数据")
private JobDataMap jobDataMap;
@ApiModelProperty(value = "cron表达式")
private String cron;
@ApiModelProperty(value = "任务描述")
private String description;
}
6、创建Controller(为了方便测试,手动添加了一些数据)
package com.feng.controller;
import com.feng.pojo.QuartzParam;
import com.feng.service.QuartzService;
import lombok.RequiredArgsConstructor;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.UUID;
/**
* quartz控制类
*
* @Author: feng
* @DateTime: 2023/11/16 20:22
*/
@RestController
@RequestMapping("/quartz")
@RequiredArgsConstructor
public class QuartzController {
@Autowired
private QuartzService quartzService;
@RequestMapping("/addJob")
public void addJob() {
QuartzParam param = new QuartzParam();
//测试数据
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("meetingId", UUID.randomUUID().toString().replace("-", ""));
jobDataMap.put("meetingName", "会议1");
jobDataMap.put("startTime", new Date());
jobDataMap.put("meetingPeople", "小明,小王,小红");
param.setJobName("meeting1");
param.setJobGroup("meetingMsg");
param.setJobDataMap(jobDataMap);
param.setJobClassName("com.feng.controller.Meeting.addMeeting()");
param.setCron("1 * * * * ?"); //1分钟执行一次
quartzService.addJob(param);
}
}
7、创建任务调度
package com.feng.service.impl;
import com.feng.job.QuartzJob;
import com.feng.pojo.QuartzParam;
import com.feng.service.QuartzService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @Author: feng
* @DateTime: 2023/11/16 20:40
*/
@Service
@Slf4j
public class QuartzServiceImpl implements QuartzService {
@Resource(name = "scheduler")
private Scheduler scheduler;
@Override
public void addJob(QuartzParam param) {
String jobName = param.getJobName();
String jobGroup = param.getJobGroup();
String cron = param.getCron();
String description = param.getDescription();
JobDataMap jobDataMap = param.getJobDataMap();
JobKey jobKey = new JobKey(jobName, jobGroup);
try {
if (scheduler.checkExists(jobKey)) {
log.error("该任务名称及任务组已存在!");
}
//创建作业调度JobDetail
JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class)
.withIdentity(jobKey) //由jobName和jobGroup组成的唯一标识
.withDescription(description) //说明
.usingJobData(jobDataMap) //用到的参数
.build();
//通过触发器名和cron 表达式创建 Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("meetingTrigger") //触发器名称
.startNow() //指定开始时间
.withSchedule(CronScheduleBuilder.cronSchedule(cron)) //cron表达式
.build();
//开启定时器
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
log.info("添加成功!- " + jobKey);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
}
8、编写任务的具体业务逻辑
package com.feng.job;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 定时器触发的任务
*
* @Author: feng
* @DateTime: 2023/11/21 19:18
*/
@Slf4j
public class QuartzJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) {
log.info("执行QuartzJob中的逻辑" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
log.info("会议信息:" + jobExecutionContext.getJobDetail().getJobDataMap().toString());
String meetingId = jobExecutionContext.getJobDetail().getJobDataMap().get("meetingId").toString();
//TODO
//会议通知消息发送逻辑
log.info("定时任务发送了会议ID为:" + meetingId + "的消息通知");
}
}
启动项目后,出现以下文字,说明已开启持久化了
执行方法后数据库中就有相关的记录,重启项目也不会丢失啦
9、删除定时任务
先调用scheduler的checkExists()方法,根据jobKey判断数据库中是否存在该定时任务,存在的话就调用deleteJob()方法删除指定定时任务。
三、总结
以上是quartz的一些使用方法,写了一个会议通知推送的简单例子,思路大概是这样。简单记录一下学习过程。