Quartz任务调度
快速入门#
任务类
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
ystem.out.println(new Date());
}
}
任务调度类
public class HelloSchedulerDemo {
public static void main(String[] args) throws Exception {
// 1、调度器(Scheduler),从工厂中获取调度的实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2、任务实例(JobDetail)
JobDetail jobDetail = JobBuilder.newJob()
.withIdentity("job1", "group1") // 参数1:任务的名称(唯一);参数2:任务组的名称
.build();
// 3、触发器(Trigger)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1") // 参数1:触发器的名称(唯一);参数2:触发器组的名称
.startNow() // 马上启动触发器
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever()) // 每2秒重复执行一次
.build();
// 4、让调度器关联任务和触发器
scheduler.scheduleJob(jobDetail, trigger);
// 5、启动
scheduler.start();
// 关闭
//scheduler.shutdown();
}
}
核心概念#
通过代码可以得到以下几个核心概念
Job
自定义的任务类都必须实现org.quartz.job
接口,并重写其中的execute()
方法
Trigger
可以简单理解为何时执行,包含 SimplerTrigger 和 CronTrigger 两种
Scheduler
将任务 Job 及触发器 Trigger 整合起来,负责基于 Trigger 设定的时间来执行 Job
Job和JobDetail#
Job
每次调度器执行Job时,它在调用execute方法前会创建一个新的 Job 实例,当调用完成后,关联的Job对象实例会被释放,释放的实例会被垃圾回收机制回收
JobDetail
为Job实例提供了许多设置属性,调度器需要借助JobDetail对象来添加Job实例
JobExecutionContext#
- 当 Scheduler 调用一个 Job,就会将 JobExecutionContext 传递给 Job 的 execute() 方法
- Job 能通过 JobExecutionContext 对象访问到 Quartz 运行时候的环境以及 Job 本身的明细数据
- 仅在Job被调用时才能通过JobExecutionContext获取运行化境数据(因为只有这时候JobExecutionContext才被传递到execute方法)
JobDataMap#
初始化信息
// 将 jobDataMap1 中数据存入 JobDetail 中
// 将 jobDataMap2 中数据存入 Trigger 中
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
//1. 调度器(Scheduler)
Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler();
JobDataMap jobDataMap1 = new JobDataMap();
jobDataMap1.put("message", "JobDetailMessage");
//2. 任务实例(JobDetail)
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "jobGroup1")
.usingJobData(jobDataMap1) // 将 JobDataMap 放入 JobDetail 中
.build();
JobDataMap jobDataMap2 = new JobDataMap();
jobDataMap2.put("message", "TriggerMessage");
//3. 触发器(Trigger)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "triggerGroup1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever())
.endAt(new Date(new Date().getTime() + 3000L))
.usingJobData(jobDataMap2) // 将 JobDataMap 放入 Trigger 中
.build();
defaultScheduler.scheduleJob(jobDetail, trigger);
defaultScheduler.start();
}
}
使用map获取#
- 用来存储特定Job实例的状态信息
- 存储在
JobExecutionContext
中
// 获取之前存入 map 中的数据
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println(jobExecutionContext.getTrigger().getJobDataMap().get("message"));
System.out.println(jobExecutionContext.getJobDetail().getJobDataMap().get("message"));
System.out.println(new Date());
}
}
使用setter获取#
Job实现类中添加setter方法对应JobDataMap的键值,Quartz框架默认的JobFactory实现类在初始化Job实例对象时会自动调用这些setter方法
@Data
public class HelloJob implements Job {
private String message;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println(message); //这里Trigger会对JobDetail进行覆盖
System.out.println(new Date());
}
}
需要注意的是:如果遇到同名
key
,Trigger中JobDataMap中的值会自动覆盖JobDetail中JobDataMap的值
Job的状态#
Job有一个StatefulJob子接口,代表有状态的任务,该接口是一个没有方法的标签接口,其目的是让Quartz知道任务的类型,以便采用不同的执行方案。无状态任务在执行时拥有自己的JobDataMap拷贝,对JobDataMap的更改不会影响下次的执行。而有状态任务共享共享同一个JobDataMap实例,每次任务执行对JobDataMap所做的更改会保存下来,后面的执行可以看到这个更改,也即每次执行任务后都会对后面的执行发生影响
正因为这个原因,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行,这意味着如果前次的StatefulJob还没有执行完毕,下一次的任务将阻塞等待,直到前次任务执行完毕。有状态任务比无状态任务需要考虑更多的因素,程序往往拥有更高的复杂度,因此除非必要,应该尽量使用无状态的Job
SimpleTrigger和CronTrigger#
SimpleTrigger#
它是为那种需要在特定的日期/时间启动,且以一个可能的间隔时间重复执行 n 次的 Job 所设计的,通过观察它的api我们就能明显的看出这个特点
- startNow()Scheduler
- 开始执行时,触发器也即执行
- startAt(new Date())
- 在指定时间开始执行
- withIntervalInSeconds(2)
- 指定间隔执行,方法名对应时间单位
- repeatForever()
- 永远执行
- withRepeatCount(3)
- 执行次数
- endAt(new Date())
- 停止时间
CronTrigger#
像日程表一样,通常基于日历进行作业,需要用cron表达式进行初始化
用这个生成吧,好使 http://cron.ciding.cc/
Scheduler#
再多废话几句:Trigger和JobDetail可以注册到Scheduler中, 两者在Scheduler中拥有各自的组及名称, 组及名称是Scheduler查找定位容器中某一对象的依据, Trigger的组及名称必须唯一, JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法, 允许外部通过组及名称访问和控制容器中Trigger和JobDetail
常用的方法
scheduler.scheduleJob(jobDetail, trigger); //绑定jobDetail与trigger
scheduler.checkExists(JobKey.jobKey(name, group)) //检查JobDetail是否存在
scheduler.checkExists(TriggerKey.triggerKey(name, group)) //检查Trigger是否存在
scheduler.deleteJob(JobKey.jobKey(name, group)) //删除jobDetail
监听器#
包含JobListener、TriggerListener、SchedulerListener三种,但是在了解这三种监听器之前,需要先了解从另一个维度对监听器的分类:全局监听器和非全局监听器
- 全局监听器能够接收到所有的Job/Trigger的事件通知
- 而非全局监听器只能接收到在其上注册的Job或者Trigger的事件,不在其上注册的Job或Trigger则不会进行监听
挖坑...以后补上监听器这块
实例#
包括添加、修改触发时间、删除
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzManager {
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
/**
* @description: 添加一个定时任务
* @param: jobName 任务名
* jobGroupName 任务组名
* triggerName 触发器名
* triggerGroupName 触发器组名
* jobClass 任务
* cron 计划时间
* @return:
* @author: lyy
* @date: 2022/7/1
*/
public static void addJob(String jobName,
String jobGroupName,
String triggerName,
String triggerGroupName,
Class jobClass,
String cron) throws Exception {
Scheduler scheduler = schedulerFactory.getScheduler();
// JobDetail jobDetail= JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
// TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// triggerBuilder.withIdentity(triggerName, triggerGroupName);
// triggerBuilder.startNow();
//任务
JobDetail jobDetail = JobBuilder.newJob().withIdentity(jobName, jobGroupName).build();
//触发器
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerName, triggerGroupName)
.startNow().withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
//绑定
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start();
}
}
/**
* @description: 修改一个任务的触发时间
* @param: [jobName, jobGroupName, triggerName, triggerGroupName, cron]
* @return:
* @author: lyy
* @date: 2022/7/1
*/
public static void modifyJobTime(String jobName,
String jobGroupName,
String triggerName,
String triggerGroupName,
String cron) throws Exception
{
Scheduler scheduler = schedulerFactory.getScheduler();
//triggerKey用于唯一标识一个trigger
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
//获取原有的
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if(trigger == null){
return ;
}
//获取原有触发时间
String oldTime = trigger.getCronExpression();
//todo:考虑是否加非空判断
if(!oldTime.equalsIgnoreCase(cron)){
//重新构造触发器赋值给trigger
trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerName, triggerGroupName)
.startNow().withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
//根据triggerKey(唯一标识)对原有trigger进行替换
scheduler.rescheduleJob(triggerKey, trigger);
}
}
/**
* @description: 移除任务
* @param: [jobName, jobGroupName, triggerName, triggerGroupName]
* @return:
* @author: lyy
* @date: 2022/7/1
*/
public static void removeJob(String jobName,
String jobGroupName,
String triggerName,
String triggerGroupName) throws Exception
{
Scheduler scheduler = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
//停止触发器
scheduler.pauseTrigger(triggerKey);
//移除触发器
scheduler.unscheduleJob(triggerKey);
//删除任务
scheduler.deleteJob(JobKey.jobKey(jobName,jobGroupName));
}
//开始和删除所有任务比较简单就不代码实现了,就是scheduler调用start()方法和shutdown()方法
}
本文内容参考
Quartz基础+实例
Quartz分布式任务调度
作者:colee51666
出处:https://www.cnblogs.com/colee51666/p/16434107.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
尊重每一个原创,从你我开始!
转载请注明原文链接,如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“👍”哦,博主在此感谢你的支持!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!