简介
Quartz是完全由Java开发的一个开源的作业调度框架。在业务系统中,主要用于做分布式定时任务。Spring本身提供的@Schedule只能实现一些相对简单的单机定时任务,如果跑定时任务的的机器出现故障,则会影响业务系统正常运行。而使用Quartz来开发分布时定时任务,将任务数据存储于数据库中,可以保证任务的单机执行,同时在执行机出现故障,则自动飘到集群中的其它机器执行,不会影响业务的正常进行。
官网:http://www.quartz-scheduler.org/
核心概念
Scheduler
: 任务调度器,可以进行调度,暂停和删除任务。
Trigger
: 触发器,描述触发任务的时间触发规则,主要使用的有两个子类,分别是:SimpleTrigger
和CronTrigger
,当任务是只需调用一次或是以固定时间间隔周期进行调用执行,使用SimpleTrigger
比较适合,当任务是以比较复杂时间规则的调用,则使用CronTrigger
比较适合,CronTrigger
的时间规则可以通过cron
表达式进行定义。
JobDetaila
: 定义任务的详情,包括了任务的唯一标识和具体要执行的任务。可通过JobDetailMap
往任务中传递数据。
Job
: 具体的任务,包括了执行任务的具体方法,是一个接口,需要实现接口的execute()
方法。
任务存储类型
RAMJobStore
: 即内存存储方式,Quartz默认启用的是内存存储类型,这种方式的性能是最好,但缺点就是缺乏持久性,在程序重启或奔溃的时候,所有的运行信息都会丢失,只能做单点,不能做分布式任务。
JDBC
: 即数据库存储方式,将定时任务数据存储到数据库后,可以做单点,也可以做分布式集群,可以对任务进行停止、暂停、修改操作,重启应用后,任务的运行信息不会丟失。
添加依赖
<!-- 添加quartz支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- 添加mysql 数据库支持 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 添加mybatis-plus支持 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 添加Druid数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.13-SNSAPSHOT</version>
</dependency>
配置
spring:
datasource: # 配置数据库信息
username: root #用户名
password: 123456789
url: jdbc:mysql://localhost:3306/quartz?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver # mysql连接驱动
type: com.alibaba.druid.pool.DruidDataSource # 启用Druid数据源
druid:
max-active: 20 # 最大连接池数量
min-idle: 5 # 最小连接池数量
quartz: # 配置quartz 信息
job-store-type: jdbc # 使用数据库存储定时任务
jdbc:
initialize-schema: embedded
overwrite-existing-jobs: true # 启动时更新己存在的Job
properties:
org:
quartz:
jobStore:
isClustered: true # 是否以集群方式运行
useProperties: false # 如果为true则表示将JobDataMaps中的所有值都作为字符串存储至数据库中
# 配置mybatis-plus信息
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
auto-mapping-behavior: full
mapper-locations: classpath:mapper/*.xml
用法
定义任务实体类
@Data
public class QuartzBean {
private String jobName;
private String groupName;
private String cron;
private Class<? extends Job> jobClass;
private JobDataMap jobDataMap;
}
定义Job类
定义一个定时任务调用执行的类,该类需要继承QuartzJobBean
,如下:
// 具体执行业务逻辑的任务类
@DisallowConcurrentExecution
public class DownloadJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
// 获取任务的参数
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
System.out.println(jobDataMap.get("one"));
System.out.println("正在执行任务");
// TODO 执行业务逻辑
}
}
任务操作
新建任务
@Service
public class QuartzService {
@Resource
private Scheduler scheduler;
/**
* 新建 JOB
* @param quartzBean
*/
public void createJob(QuartzBean quartzBean) throws SchedulerException {
// 生成JobKey,针对Job唯一识别
JobKey jobKey = JobKey.jobKey(quartzBean.getJobName(), quartzBean.getGroupName());
// 生成JobDetail对象,构建定时任务信息
JobDetail jobDetail = JobBuilder.newJob(quartzBean.getJobClass()).withIdentity(jobKey).setJobData(quartzBean.getJobDataMap()).build();
// 构建Cron表达式,即构建定时任务执行方式
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCron());
// 生成TriggerKey,针对Trigger的唯一识别
TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName(), quartzBean.getGroupName());
// 构建Trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
// 将Job与Trigger传入到scheduler调度器中
scheduler.scheduleJob(jobDetail, trigger);
// 启动调度器
scheduler.start();
}
}
一次性任务
@Service
public class QuartzService {
@Resource
private Scheduler scheduler;
/**
* 一次性任务,即只执行一次
* @param quartzBean
* @throws SchedulerException
*/
public void oneWayJob(QuartzBean quartzBean) throws SchedulerException {
// 生成JobKey,针对Job唯一识别
JobKey jobKey = JobKey.jobKey(quartzBean.getJobName(), quartzBean.getGroupName());
// 生成JobDetail对象,构建定时任务信息
JobDetail jobDetail = JobBuilder.newJob(quartzBean.getJobClass()).withIdentity(jobKey).setJobData(quartzBean.getJobDataMap()).build();
// 生成TriggerKey,针对Trigger的唯一识别
TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName(), quartzBean.getGroupName());
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(SimpleScheduleBuilder.simpleSchedule().withRepeatCount(0)).build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}
}
暂停任务
@Service
public class QuartzService {
@Resource
private Scheduler scheduler;
/**
* 暂停JOB
* @param quartzBean
*/
public void pauseJob(QuartzBean quartzBean) throws SchedulerException {
JobKey jobKey = JobKey.jobKey(quartzBean.getJobName(), quartzBean.getGroupName());
scheduler.pauseJob(jobKey);
}
}
恢复任务
@Service
public class QuartzService {
@Resource
private Scheduler scheduler;
/**
* 恢复JOB
* @param quartzBean
*/
public void resumeJob(QuartzBean quartzBean) throws SchedulerException {
JobKey jobKey = JobKey.jobKey(quartzBean.getJobName(), quartzBean.getGroupName());
scheduler.resumeJob(jobKey);
}
}
删除任务
@Service
public class QuartzService {
@Resource
private Scheduler scheduler;
/**
* 删除JOB
* @param quartzBean
*/
public void deleteJob(QuartzBean quartzBean) throws SchedulerException {
JobKey jobKey = JobKey.jobKey(quartzBean.getJobName(), quartzBean.getGroupName());
scheduler.deleteJob(jobKey);
}
}
获取所有任务
@Service
public class QuartzService {
@Resource
private Scheduler scheduler;
/**
* 获取所有计划中的任务列表
* @return
* @throws SchedulerException
*/
public List<Map<String, String>> queryAllJob() throws SchedulerException {
List<Map<String, String>> jobList = null;
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeySet = scheduler.getJobKeys(matcher);
for (JobKey jobKey : jobKeySet) {
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
List<Map<String, String>> jobs = triggers.stream().map(trigger -> {
try {
Map<String, String> map = new HashMap<>();
map.put("jobName", jobKey.getName());
map.put("jobGroupName", jobKey.getGroup());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
map.put("status", triggerState.name());
if(trigger instanceof CronTrigger){
CronTrigger cronTrigger = (CronTrigger) trigger;
map.put("cron", cronTrigger.getCronExpression());
}
return map;
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
jobList.addAll(jobs);
}
return jobList;
}
}
任务调用
在Controller中调用相关的任务,下面以新增JOB为例,如下:
@RestController
@RequestMapping("task")
public class QuartzController {
@Autowired
private QuartzService quartzService;
@PostMapping
public String createJob() throws SchedulerException {
QuartzBean quartzBean = new QuartzBean();
quartzBean.setCron("*/5 * * * * ?");
quartzBean.setJobName("TestJob");
quartzBean.setGroupName("GroupJob");
quartzBean.setJobClass(DownloadJob.class);
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("one", "Test");
quartzBean.setJobDataMap(jobDataMap);
quartzService.createJob(quartzBean);
return "SUCCESS";
}
}
原创文章,作者:jiafegn,如若转载,请注明出处:https://www.techlearn.cn/archives/1977