在开发过程中,我们会用定时任务来执行一些 *** 作,例如定时去捞取流水重试业务、定时去消息中间件获取消息等等相关需求
简单的定时任务实现可以借助Spring提供的 @Scheduled 注解 详细看 Spring 原理之 Scheduled
如果涉及到 定时任务的动态管理就需要使用到其他技术,下面介绍一下Quartz
Quartz是一个开源的任务日程管理系统, 由 OpenSymphony开源,同时它是一个功能丰富的任务调用系统,可创建简单或者复杂的几十、几百、甚至成千上万的job。除此之外,quartz调度器还支持JTA事务和集群。
Maven 的pom.xml文件引入相关依赖包
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
Quarz使用
1、总体介绍
- org.quarz
说明:
Quarz 包中包含了三大要素
- Scheduler:核心,任务调度器
- Trigger:触发器,定义job执行的方式、间隔。
- JobDetail & Job : 具体任务,用来定义任务执行的具体逻辑
JobDetail & Job 是指具体任务,用来定义任务执行的具体逻辑
2.1 创建一般配套使用,下面分别介绍 Job 、 JobDetail 、 JobBuilder
- org.quarz.Job
只有一个方法,一般通过实现该接口 自定义自己的Job
public interface Job {
/**
* 执行
*/
void execute(JobExecutionContext context)
throws JobExecutionException;
}
- org.quarz.JobDetail
常用的方法,自定义好Job之后,创建 JobDetail :
public interface JobDetail extends Serializable, Cloneable {
/**
* JobDetail 的唯一身份
*/
public JobKey getKey();
/**
* 描述
*/
public String getDescription();
/**
* 获取到JobDetail关联的job class
*/
public Class<? extends Job> getJobClass();
/**
* 与job相关的状态属性
*/
public JobDataMap getJobDataMap();
/**
* JobDeatil创建使用的 JobBuilder
*/
public JobBuilder getJobBuilder();
}
// JobKey 继承Key
// 主要有两个属性:
//private final String name;
//private final String group; 默认为 "DEFAULT"
public final class JobKey extends Key<JobKey> {
private static final long serialVersionUID = -6073883950062574010L;
public JobKey(String name) {
super(name, null); // group 默认为 "DEFAULT"
}
public JobKey(String name, String group) {
super(name, group);
}
}
// JobDataMap:实质上就是HashMap来存储key、Value,用于多次执行Job的时候来跟踪Job的状态 JobDataMap中可以包含不限量的(序列化的)数据对象,在job实例执行的时候,可以使用其中的数据
- org.quarz.JobBuilder
用于创建 JobDetail,常用的方法如下:
方法名称 | 描述 |
---|---|
newJob | 创建一个 JobBuilder ,指定Job的JobBuilder / 默认的JobBuilder |
build | 利用 JobBuilder 创建 JobDetail |
withIdentity | 创建 JobKey,多种重载方法,指定JobKey中的 name / group |
usingJobData | 往默认的 JobDataMap(如果没设置) 中的 key 设置 value |
setJobData | 设置 JobDataMap |
public class JobBuilder {
private JobKey key;
private String description;
private Class<? extends Job> jobClass;
private boolean durability; // 如果一个job是非持久的,当没有活跃的trigger与之关联的时候,会被自动地从scheduler中删除。也就是说,非持久的job的生命期是由trigger的存在与否决定的;
private boolean shouldRecover; // cheduler发生硬关闭(hard shutdown)(比如运行的进程崩溃了,或者关机了),则当scheduler重新启动的时候,该job是否被重新执行
private JobDataMap jobDataMap = new JobDataMap();
protected JobBuilder() {
}
/**
* 创建 JobBuilder
*/
public static JobBuilder newJob() {
return new JobBuilder();
}
/**
* 指定job的 JobBuilder
*/
public static JobBuilder newJob(Class <? extends Job> jobClass) {
JobBuilder b = new JobBuilder();
b.ofType(jobClass);
return b;
}
/**
* 创建 JobDetail
*/
public JobDetail build() {
JobDetailImpl job = new JobDetailImpl();
job.setJobClass(jobClass);
job.setDescription(description);
if(key == null)
key = new JobKey(Key.createUniqueName(null), null);
job.setKey(key);
job.setDurability(durability);
job.setRequestsRecovery(shouldRecover);
if(!jobDataMap.isEmpty())
job.setJobDataMap(jobDataMap);
return job;
}
/**
* 设置 JobKey
*/
public JobBuilder withIdentity(String name) {
key = new JobKey(name, null);
return this;
}
/**
* 设置 JobKey
*/
public JobBuilder withIdentity(String name, String group) {
key = new JobKey(name, group);
return this;
}
/**
* 设置 jobKey
*/
public JobBuilder withIdentity(JobKey jobKey) {
this.key = jobKey;
return this;
}
/**
* 设置 JobBuilder 的 job class
*/
public JobBuilder ofType(Class <? extends Job> jobClazz) {
this.jobClass = jobClazz;
return this;
}
// 设置 newJobDataMap,也有单独的 根据key 设置 value的多个重载方法
public JobBuilder usingJobData(JobDataMap newJobDataMap) {
jobDataMap.putAll(newJobDataMap);
return this;
}
/**
* 根据key 设置 value的多个重载方法
*/
public JobBuilder usingJobData(String dataKey, Boolean value) {
jobDataMap.put(dataKey, value);
return this;
}
// 设置 JobDataMap
public JobBuilder setJobData(JobDataMap newJobDataMap) {
jobDataMap = newJobDataMap;
return this;
}
}
上面几种类/接口的关系:(Job与JobDetail通过 JobBuilder 产生联系)
- JobBuilder :设置 Job , 设置 Job的状态 JobDataMap
- JobBuilder: 创建 JobDetail 的唯一标识 JobKey
1)关于Job的使用,一般会接口实现来完成我们自己的一些业务 *** 作(如持久化、状态跟踪)
example:
// 简单使用
public class ExecuteJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("ExecuteJob 正在执行");
}
}
// 复杂使用
public class ExecuteJob implements Job {
// context 里面包含了很多方法,常用的如下
// getScheduler:获取Scheduler
// getTrigger:获取触发器Trigger
//getJobDetail:获取JobDetail
//getJobInstance:获取到Job
// getMergedJobDataMap:获取 JobDetail中的JobDataMap和Trigger中的JobDataMap的并集,但是如果存在相同的数据,则后者会覆盖前者的值
public void execute(JobExecutionContext context)
throws JobExecutionException {
// 获取 JobDetail 的 JobKey
JobKey key = context.getJobDetail().getKey();
// 获取 JobDetail中的JobDataMap和Trigger中的JobDataMap的并集
JobDataMap dataMap = context.getMergedJobDataMap();
// 获取创建 JobDetail 设置的值
String AString = dataMap.getString("AString");
float BFloatValue = dataMap.getFloat("BFloatValue");
ArrayList CList = (ArrayList) dataMap.get("CList");
System.out.println("Instance " + key + " of AString : " + AString + ", and BFloatValue is: " + BFloatValue);
}
}
2)关于JobDeatil的使用
example:
// quartzJob 是与数据库相关的DO,用其id来构造JobKey保证唯一性
private JobDetail createJobDetail(QuartzJob quartzJob){
String JOB_NAME = "TASK_"; // JobKey的名称前缀
return JobBuilder.newJob(ExecuteJob.class). // 指定Job 的JobBuilder
withIdentity(JOB_NAME + quartzJob.getId()).build(); // 创建
}
private JobDetail createJobDetail(QuartzJob quartzJob){
String JOB_NAME = "TASK_";
return JobBuilder.newJob(ExecuteJob.class).
withIdentity(JOB_NAME + quartzJob.getId())
.usingJobData("AString" , "i am a string ") // 指定 JobDataMap 的key value
.usingJobData("BFloatValue" , 0F) // 指定 JobDataMap 的key value
.build(); // 创建
}
3、Trigger
Trigger 是指具体任务,触发器,定义job执行的方式、间隔。
3.1 创建其跟 JobDetail 很像,一般也涉及到 Trigger 、 TriggerKey、TriggerBuilder
TriggerKey 与 JobKey 类似,都是有 name、group属性,用于唯一标识 Trigger,group默认为 “DEFAULT”
- org.quarz.Trigger
Trigger 是一个接口,目前Quartz包里面已经有一些实现类
常用方法:
方法名称 | 描述 |
---|---|
getKey | 获取 TriggerKey |
getJobKey | 获取 JobKey |
getJobDataMap | 获取 JobDataMap |
getStartTime getEndTime getPreviousFireTime getNextFireTime getFinalFireTime getFireTimeAfter(Date afterTime) | 触发器的时间 开始时间、截止时间 上次触发时间 下次触发时间 最后触发时间 在afterTime后的下次触发时间 |
getTriggerBuilder | 获取 TriggerBuiler |
getScheduleBuilder | 获取 ScheduleBuilder |
实现类:(不同的实现类上述方法实现略有不同,基本上都是很简单的Date、Calendar、TimeZone的一些设置与比较)
接口 | 实现类 | 描述 |
---|---|---|
CalendarIntervalTrigger | CalendarIntervalTriggerImpl | 触发任务 基于重复的日历时间间隔 |
CronTrigger | CronTriggerImpl | 触发任务 基于Cron表达式 |
DailyTimeIntervalTrigger | DailyTimeIntervalTriggerImpl | 触发任务 在给定的时间点,并且可以选择以指定的间隔重复 |
SimpleTrigger | SimpleTriggerImpl | 触发任务 基于每天重复的时间间隔 |
- org.quarz.TriggerBuilder
用于创建 Trigger,常用的方法如下:
方法名称 | 描述 |
---|---|
newTrigger | 创建一个 TriggerBuilder,new TriggerBuilder() |
build | 利用 TriggerBuilder 创建 Trigger |
withIdentity | 设置TriggerKey,多种重载方法,指定TriggerKey中的 name / group |
forJob | 设置 JobKey,多种重载方法,指定JobKey中的 name / group |
usingJobData | 往默认的 JobDataMap(如果没设置) 中的 key 设置 value |
startNow | trigger 立即执行 |
startAt(Date triggerStartTime) | 在 指定时间 开始执行(设置 startTime) |
endAt(Date triggerEndTime) | 在 指定时间 结束执行(设置 endTime) |
withSchedule | 指定触发器Trigger的Scheduler |
public class TriggerBuilder<T extends Trigger> {
private TriggerKey key;
private String description;
private Date startTime = new Date();
private Date endTime;
private int priority = Trigger.DEFAULT_PRIORITY;
private String calendarName;
private JobKey jobKey;
private JobDataMap jobDataMap = new JobDataMap();
private ScheduleBuilder<?> scheduleBuilder = null;
private TriggerBuilder() {
}
/**
* 创建 TriggerBuilder
*/
public static TriggerBuilder<Trigger> newTrigger() {
return new TriggerBuilder<Trigger>();
}
/**
* 创建 Trigger
*/
@SuppressWarnings("unchecked")
public T build() {
if(scheduleBuilder == null)
scheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
MutableTrigger trig = scheduleBuilder.build();
trig.setCalendarName(calendarName);
trig.setDescription(description);
trig.setStartTime(startTime);
trig.setEndTime(endTime);
if(key == null)
key = new TriggerKey(Key.createUniqueName(null), null);
trig.setKey(key);
if(jobKey != null)
trig.setJobKey(jobKey);
trig.setPriority(priority);
if(!jobDataMap.isEmpty())
trig.setJobDataMap(jobDataMap);
return (T) trig;
}
/** 设置 TriggerKey 三种重载方法
* withIdentity(String name, String group)
* withIdentity(TriggerKey triggerKey)
* withIdentity(String name)
*/
public TriggerBuilder<T> withIdentity(TriggerKey triggerKey) {
this.key = triggerKey;
return this;
}
/**
* 设置开始执行时间
*/
public TriggerBuilder<T> startAt(Date triggerStartTime) {
this.startTime = triggerStartTime;
return this;
}
/**
* 立即执行
*/
public TriggerBuilder<T> startNow() {
this.startTime = new Date();
return this;
}
/**
* 设置结束时间
*/
public TriggerBuilder<T> endAt(Date triggerEndTime) {
this.endTime = triggerEndTime;
return this;
}
/**
* 设置 SchedulerBuiler 来创建 Trigger's schedule.
*/
@SuppressWarnings("unchecked")
public <SBT extends T> TriggerBuilder<SBT> withSchedule(ScheduleBuilder<SBT> schedBuilder) {
this.scheduleBuilder = schedBuilder;
return (TriggerBuilder<SBT>) this;
}
/**
设置 JobKey 三种重载方法
* forJob(JobKey keyOfJobToFire)
* forJob(JobDetail jobDetail)
* forJob(String jobName, String jobGroup)
* forJob(String jobName)
*/
public TriggerBuilder<T> forJob(JobDetail jobDetail) {
JobKey k = jobDetail.getKey();
if(k.getName() == null)
throw new IllegalArgumentException("The given job has not yet had a name assigned to it.");
this.jobKey = k;
return this;
}
/**
* 设置Trigger 的 JobDataMap
*/
public TriggerBuilder<T> usingJobData(JobDataMap newJobDataMap) {
// add any existing data to this new map
for(String dataKey: jobDataMap.keySet()) {
newJobDataMap.put(dataKey, jobDataMap.get(dataKey));
}
jobDataMap = newJobDataMap; // set new map as the map to use
return this;
}
/**
* 根据key设置Value ,多种 重载方法,value的类型不同
*/
public TriggerBuilder<T> usingJobData(String dataKey, Boolean value) {
jobDataMap.put(dataKey, value);
return this;
}
}
3.2 使用
1)关于 Trigger 的使用,会根据
example:
//通过触发器名和cron 表达式创建 Trigger
// quartzJob 是与数据库相关的DO,用其id来构造TriggerKey保证唯一性
private Trigger createTrigger(QuartzJob quartzJob){
String JOB_NAME = "TASK_"; // TriggerKey的 名称前缀
return newTrigger()
.withIdentity(JOB_NAME + quartzJob.getId()) // TriggerKey 的设置
.startNow() // 立即执行
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression())) // 根据Corne表达式执行Scheduler
.build(); // 创建
}
4、Scheduler
scheduler 是quartz的核心所在,所有的任务都是通过scheduler开始
4.1 创建Scheduler是一个接口,使用工厂模式创建,通过SchedulerFactory工厂类实现
- org.quarz.SchedulerFactory
public interface SchedulerFactory {
// 获取一个可用的Scheduler
Scheduler getScheduler() throws SchedulerException;
// 根据name获取Scheduler
Scheduler getScheduler(String schedName) throws SchedulerException;
// 获取所有的Scheduler
Collection<Scheduler> getAllSchedulers() throws SchedulerException;
}
其有两个具体的实现类:**DirectSchedulerFactory **和 StdSchedulerFactory,核心的创建都是通过 SchedulerRepository
- **DirectSchedulerFactory **:根据默认配置,单例创建Scheduler
- StdSchedulerFactory:根据配置文件相关配置创建Scheduler,配置文件为当前工作目录下的 quartz.properties 属性文件。如果没有该文件/加载失败,会加载org/quartz包下的 quartz.properties 属性文件,也可自己制定其他的properties来设置参数值
DirectSchedulerFactory 核心方法:
方法名称 | 方法 | 描述 |
---|---|---|
createScheduler | 实例方法 | 创建一个Scheduler 由很多重载方法,根据参数不同 schedulerName(默认 SimpleQuartzScheduler) schedulerInstanceId(默认SIMPLE_NON_CLUSTERED) threadPool(需指定) jobStore(需指定) |
getScheduler | 实例方法 | 还是调用getScheduler(String name)创建,name为默认的 SimpleQuartzScheduler |
getScheduler(String name) | 实例方法 | 返回一个指定name的Scheduler |
getAllSchedulers | 实例方法 | 获取到所有可用的 Scheduler |
StdSchedulerFactory 常用方法
方法名称 | 方法 | 描述 |
---|---|---|
getSchedulerName | 实例方法 | 配置文件中org.quartz.scheduler.instanceName(DefaultQuartzScheduler) 若无配置默认为 QuartzScheduler |
getDefaultScheduler | 静态方法 | 返回一个默认的 Scheduler,内部还是调用 getScheduler()方法实现的 |
getScheduler | 实例方法 | 利用 SchedulerRepository 创建一个Scheduler,如果没有才创建 |
getScheduler(String name) | 实例方法 | 返回一个指定name的Scheduler |
getAllSchedulers | 实例方法 | 获取到所有可用的 Scheduler |
- org.quarz.quartz.properties
-----jar包自带的一些配置------
# scheduler的配置
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
# 线程池的相关配置
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
#指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
org.quartz.threadPool.threadCount: 10
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
#设置是否为守护线程
org.quartz.jobStore.misfireThreshold: 60000
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
-----扩展的一些配置------
#设置SimpleThreadPool的一些属性
#设置是否为守护线程
#org.quartz.threadpool.makethreadsdaemons = false
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
#org.quartz.threadpool.threadsinheritgroupofinitializingthread=false
#线程前缀默认值是:[Scheduler Name]_Worker
#org.quartz.threadpool.threadnameprefix=swhJobThead;
# 配置全局监听(TriggerListener,JobListener) 则应用程序可以接收和执行 预定的事件通知
# ===========================================================================
# Configuring a Global TriggerListener 配置全局的Trigger监听器
# MyTriggerListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.triggerListener.NAME.class = com.swh.MyTriggerListenerClass
#org.quartz.triggerListener.NAME.propName = propValue
#org.quartz.triggerListener.NAME.prop2Name = prop2Value
# ===========================================================================
# Configuring a Global JobListener 配置全局的Job监听器
# MyJobListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.jobListener.NAME.class = com.swh.MyJobListenerClass
#org.quartz.jobListener.NAME.propName = propValue
#org.quartz.jobListener.NAME.prop2Name = prop2Value
# ===========================================================================
# Configure JobStore 存储调度信息(工作,触发器和日历等)
# ===========================================================================
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold: 60000
#保存job和Trigger的状态信息到内存中的类
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
# ===========================================================================
# Configure SchedulerPlugins 插件属性 配置
# ===========================================================================
# 自定义插件
#org.quartz.plugin.NAME.class = com.swh.MyPluginClass
#org.quartz.plugin.NAME.propName = propValue
#org.quartz.plugin.NAME.prop2Name = prop2Value
#配置trigger执行历史日志(可以看到类的文档和参数列表)
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin
org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}
org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}
#配置job调度插件 quartz_jobs(jobs and triggers内容)的XML文档
#加载 Job 和 Trigger 信息的类 (1.8之前用:org.quartz.plugins.xml.JobInitializationPlugin)
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
#指定存放调度器(Job 和 Trigger)信息的xml文件,默认是classpath下quartz_jobs.xml
org.quartz.plugin.jobInitializer.fileNames = my_quartz_job2.xml
#org.quartz.plugin.jobInitializer.overWriteExistingJobs = false
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
#自动扫描任务单并发现改动的时间间隔,单位为秒
org.quartz.plugin.jobInitializer.scanInterval = 10
#覆盖任务调度器中同名的jobDetail,避免只修改了CronExpression所造成的不能重新生效情况
org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
# Configure RMI Settings 远程服务调用配置
#如果你想quartz-scheduler出口本身通过RMI作为服务器,然后设置“出口”标志true(默认值为false)。
#org.quartz.scheduler.rmi.export = false
#主机上rmi注册表(默认值localhost)
#org.quartz.scheduler.rmi.registryhost = localhost
#注册监听端口号(默认值1099)
#org.quartz.scheduler.rmi.registryport = 1099
#创建rmi注册,false/never:如果你已经有一个在运行或不想进行创建注册
# true/as_needed:第一次尝试使用现有的注册,然后再回来进行创建
# always:先进行创建一个注册,然后再使用回来使用注册
#org.quartz.scheduler.rmi.createregistry = never
#Quartz Scheduler服务端端口,默认是随机分配RMI注册表
#org.quartz.scheduler.rmi.serverport = 1098
#true:链接远程服务调度(客户端),这个也要指定registryhost和registryport,默认为false
# 如果export和proxy同时指定为true,则export的设置将被忽略
#org.quartz.scheduler.rmi.proxy = false
example:
Scheduler scheduler = null;
scheduler = StdSchedulerFactory.getDefaultScheduler();
4.2 使用
常用的一些方法:
方法名称 | 描述 |
---|---|
start startDelayed(int) isStarted | 开始 Scheduler 线程、立即开启/延迟开启、是否开启线程 |
shutdown shutdown(boolean) isShutdown | 关闭Scheduler线程,立即关闭/等待所有job执行完关闭、是否关闭线程 |
scheduleJob | 设置定时任务 指定 JobDetail 与 trigger |
triggerJob | 立即执行定时任务 |
unscheduleJob | 去除job的Trigger |
rescheduleJob | 去除job的Trigger,重新配置新Trigger(之前的定时任务配置被删除) |
resumeJob | 恢复执行定时任务 |
pauseJob | 暂停执行定时任务 |
deleteJob | 删除定时任务 |
涉及重载方法如下:
// 为指定的JobDetail 指定 Trigger
Date scheduleJob(JobDetail jobDetail, Trigger trigger)
throws SchedulerException;
/**
* 为Scheduler默认的job 指定trigger
*/
Date scheduleJob(Trigger trigger) throws SchedulerException;
/**
* 批量配置 triggersAndJobs
* 如果job的key不唯一或者已经存在,replace 要设置为true,否则抛出异常
*/
void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException;
/**
* 为指定的 jobDetail 配置多个Trigger
* 如果job的key不唯一或者已经存在,replace 要设置为true,否则抛出异常
*/
void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) throws SchedulerException;
2)、triggerJob 立即执行定时任务 指定 job 与 trigger
涉及重载方法如下:
/**
* 立即执行,这里传入的是 JobDetail 的jobKey
*/
void triggerJob(JobKey jobKey)
throws SchedulerException;
/**
* 立即执行,这里传入的是 JobDetail 的jobKey
* data 用来设置关联的 Trigger 的JobDataMap
*/
void triggerJob(JobKey jobKey, JobDataMap data)
throws SchedulerException;
3)、unscheduleJob 去除job的Trigger
/**
* 单个取消,这里传入 Trigger 的TriggerKey
*/
boolean unscheduleJob(TriggerKey triggerKey)
throws SchedulerException;
/**
* 批量取消,这里传入 Trigger 的TriggerKey List
*/
boolean unscheduleJobs(List<TriggerKey> triggerKeys)
throws SchedulerException;
4)、rescheduleJob 去除job的Trigger 重新配置新Trigger
/**
* 删除 triggerKey 的Trigger ,然后配置一个新的newTrigger , 对同一个Job *** 作
*/
Date rescheduleJob(TriggerKey triggerKey, Trigger newTrigger)
throws SchedulerException;
5)、pauseJob、resumeJob 暂停/恢复job
/**
* 根据 jobKey 暂停 Job
*/
void pauseJob(JobKey jobKey)
throws SchedulerException;
/**
* 根据 Group来 暂停 一组Job
*/
void pauseJobs(GroupMatcher<JobKey> matcher) throws SchedulerException;
/**
* 根据 jobKey 恢复 Job
*/
void resumeJob(JobKey jobKey)
throws SchedulerException;
/**
* 根据 Group来 恢复 一组Job
*/
void resumeJobs(GroupMatcher<JobKey> matcher) throws SchedulerException;
6)、deleteJob 删除job
/**
* 根据 jobKey 删除 Job
*/
boolean deleteJob(JobKey jobKey)
throws SchedulerException;
/**
* 根据 jobKey 批量删除 Job
*/
boolean deleteJobs(List<JobKey> jobKeys)
throws SchedulerException;
example:
public class QuartzManager {
// 增加定时任务
public void addJob(QuartzJob quartzJob) {
try {
// 构建job信息
JobDetail jobDetail = createJobDetail(quartzJob);
//通过触发器名和cron 表达式创建 Trigger
Trigger cronTrigger = createTrigger(quartzJob);
cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
//重置启动时间
((CronTriggerImpl) cronTrigger).setStartTime(new Date());
// 创建Scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 启动线程 ,非常重要
scheduler.start();
//执行定时任务
scheduler.scheduleJob(jobDetail, cronTrigger);
} catch (Exception e) {
log.error("创建定时任务失败", e);
}
}
// 创建JobDetail
private JobDetail createJobDetail(QuartzJob quartzJob) {
String JOB_NAME = "TASK_";
return JobBuilder.newJob(ExecuteJob.class).
withIdentity(JOB_NAME + quartzJob.getId())
.usingJobData("AString", "i am a string ")
.usingJobData("BFloatValue", 0F)
.build();
}
// 创建Trigger
private Trigger createTrigger(QuartzJob quartzJob) {
String JOB_NAME = "TASK_";
return newTrigger()
.withIdentity(JOB_NAME + quartzJob.getId())
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
.build();
}
}
// 项目 runner
@Component
@RequiredArgsConstructor
public class JobRunner implements ApplicationRunner {
private static final Logger log = LoggerFactory.getLogger(JobRunner.class);
private final QuartzManager quartzManager;
/**
* 项目启动时重新激活启用的定时任务
*
* @param applicationArguments /
*/
@Override
public void run(ApplicationArguments applicationArguments) {
log.info("--------------------注入系统定时任务------------------");
// 一般这里可以从数据库获取到大量的QuartzJob ,然后将这些都注入到定时任务中
QuartzJob job = new QuartzJob();
job.setId(1l);
job.setCronExpression("0/1 * * * * ?");
quartzManager.addJob(job);
log.info("--------------------定时任务注入完成------------------");
}
}
// QuartzJob
@Getter
@Setter
public class QuartzJob implements Serializable {
private Long id;
private String cronExpression;
}
# 输出
Instance DEFAULT.TASK_1 of AString : i am a string , and BFloatValue is: 0.0
Instance DEFAULT.TASK_1 of AString : i am a string , and BFloatValue is: 0.0
Instance DEFAULT.TASK_1 of AString : i am a string , and BFloatValue is: 0.0
Instance DEFAULT.TASK_1 of AString : i am a string , and BFloatValue is: 0.0
Instance DEFAULT.TASK_1 of AString : i am a string , and BFloatValue is: 0.0
Instance DEFAULT.TASK_1 of AString : i am a string , and BFloatValue is: 0.0
总结
简单的使用定时任务 基本上使用Spring的Schedule来实现功能即可,但是其不能动态的管理
如果需要动态的管理,可以用 Quartz 来实现,常见的一些方法列举出来了,具体使用还要依靠具体使用,大家也可去看看源码,简单易懂,底层原理等其他博客~
一个封装小例子:
package study;
import lombok.extern.slf4j.Slf4j;
import me.quartz.domain.QuartzJob;
import me.quartz.domain.ExecuteJob;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import static org.quartz.TriggerBuilder.newTrigger;
@Slf4j
@Component
public class QuartzManage {
private static final String JOB_NAME = "TASK_";
@Resource
private Scheduler scheduler;
public void addJob(QuartzJob quartzJob){
try {
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(ExecuteJob.class).
withIdentity(JOB_NAME + quartzJob.getId()).build();
//通过触发器名和cron 表达式创建 Trigger
Trigger cronTrigger = newTrigger()
.withIdentity(JOB_NAME + quartzJob.getId())
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
.build();
cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
//重置启动时间
((CronTriggerImpl)cronTrigger).setStartTime(new Date());
//执行定时任务
scheduler.scheduleJob(jobDetail,cronTrigger);
// 暂停任务
if (quartzJob.getIsPause()) {
pauseJob(quartzJob);
}
} catch (Exception e){
log.error("创建定时任务失败", e);
}
}
/**
* 更新job cron表达式
* @param quartzJob /
*/
public void updateJobCron(QuartzJob quartzJob){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
if(trigger == null){
addJob(quartzJob);
trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
}
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression());
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//重置启动时间
((CronTriggerImpl)trigger).setStartTime(new Date());
trigger.getJobDataMap().put(QuartzJob.JOB_KEY,quartzJob);
scheduler.rescheduleJob(triggerKey, trigger);
// 暂停任务
if (quartzJob.getIsPause()) {
pauseJob(quartzJob);
}
} catch (Exception e){
log.error("更新定时任务失败", e);
}
}
/**
* 删除一个job
* @param quartzJob /
*/
public void deleteJob(QuartzJob quartzJob){
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.pauseJob(jobKey);
scheduler.deleteJob(jobKey);
} catch (Exception e){
log.error("删除定时任务失败", e);
}
}
/**
* 恢复一个job
* @param quartzJob /
*/
public void resumeJob(QuartzJob quartzJob){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
if(trigger == null) {
addJob(quartzJob);
}
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.resumeJob(jobKey);
} catch (Exception e){
log.error("恢复定时任务失败", e);
}
}
/**
* 立即执行job
* @param quartzJob /
*/
public void runJobNow(QuartzJob quartzJob){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
if(trigger == null) {
addJob(quartzJob);
}
JobDataMap dataMap = new JobDataMap();
dataMap.put(QuartzJob.JOB_KEY, quartzJob);
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.triggerJob(jobKey,dataMap);
} catch (Exception e){
log.error("定时任务执行失败", e);
}
}
/**
* 暂停一个job
* @param quartzJob /
*/
public void pauseJob(QuartzJob quartzJob){
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.pauseJob(jobKey);
} catch (Exception e){
}
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)