定时任务
2020-05-22 本文已影响0人
超级笔记本
Schedule
1、注意事项
- @Scheduled(cron = "0/5 * * * * ?") 注解方法
- @EnableScheduling 注解启动类
- 如果是@Service中的方法,引入 import org.springframework.stereotype.Service; 不是dubbo的
- 适合简单的定时任务,过多的任务可能导致阻塞,崩溃,延迟启动等问题。
2、表达式
1010726-20190919020734351-1528359096.pngQuartz
1、基本要素
- Scheduler:调度器。所有的调度都是由它控制。
- Trigger: 触发器。决定什么时候来执行任务。
- JobDetail & Job: JobDetail定义的是任务数据,而真正的执行逻辑是在Job中。使用JobDetail + Job而不是Job,这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。
2、引入依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.3</version>
</dependency>
3、持久化配置(系统重启,自动查询数据库中的任务来启动)
[quartz官网地址,下载压缩包,找到sql文件]{http://www.quartz-scheduler.org/downloads/}
spring:
quartz:
#相关属性配置
properties:
org:
quartz:
scheduler:
#调度器实例名称
instanceName: clusteredScheduler
#调度器实例编号自动生成
instanceId: AUTO
jobStore:
#持久化方式配置
class: org.quartz.impl.jdbcjobstore.JobStoreTX
#持久化方式配置数据驱动,MySQL数据库
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#quartz相关数据表前缀名
tablePrefix: QRTZ_
#开启分布式部署
isClustered: true
#分布式节点有效性检查时间间隔,单位:毫秒
clusterCheckinInterval: 10000
#配置是否使用
useProperties: false
threadPool:
#线程池实现类
class: org.quartz.simpl.SimpleThreadPool
#执行最大并发线程数量
threadCount: 10
#线程优先级
threadPriority: 5
#配置是否启动自动加载数据库内的定时任务,默认true
threadsInheritContextClassLoaderOfInitializingThread: true
#数据库方式
job-store-type: jdbc
#初始化表结构
jdbc:
initialize-schema: always
4、实现Job接口
- 执行任务处理
public class BaseJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//todo
}
}
- 反射方式调用方法
//同一个容器中 注入applicationContext
@Autowired
private ApplicationContext applicationContext;
···
Object service = applicationContext.getBean(serviceName)
···
//不同一个容器中 注入registryConfig
@Autowired
private RegistryConfig registryConfig;
···
ReferenceBean referenceBean = new ReferenceBean();
referenceBean.setRegistry(registryConfig);
referenceBean.setInterface(serviceName);
Object service = referenceBean.getObject();
5、任务管理类
在处理自己的业务同时,调用管理类进行任务管理,比如记录日志
package com.firstniu.venus.quartz.utils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 定时任务管理类
*/
@Component
public class QuartzManager {
/**
* 注入任务调度器
*/
@Autowired
private Scheduler scheduler;
/**
* 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名 (带参数)
*
* @param jobName 任务名
* @param cls 任务
* @param time 时间设置,参考quartz说明文档
*/
public void addJob(String jobName, String jobGroup, Class<? extends Job> cls, String time, Map<String, Object> param) {
try {
JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(jobName, jobGroup).build(); //用于描叙Job实现类及其他的一些静态信息,构建一个作业实例
jobDetail.getJobDataMap().putAll(param); //传参数
CronTrigger trigger = TriggerBuilder
.newTrigger() //创建一个新的TriggerBuilder来规范一个触发器
.withIdentity(jobName, jobGroup) //给触发器起一个名字和组名
.withSchedule(CronScheduleBuilder.cronSchedule(time))
.build();
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start(); // 启动
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改一个任务的触发时间(触发器名,触发器组名)
*
* @param jobName
* @param jobGroup
* @param time
* @param param
*/
public void modifyJobTime(String jobName, String jobGroup, String time, Map<String, Object> param) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); //通过触发器名和组名获取TriggerKey
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); //通过TriggerKey获取CronTrigger
if (trigger == null) {
return;
}
trigger.getJobDataMap().putAll(param);
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroup); //通过任务名和组名获取JobKey
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
Class<? extends Job> objJobClass = jobDetail.getJobClass();
removeJob(jobName, jobGroup);
addJob(jobName, jobGroup, objJobClass, time, param);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改一个任务的触发时间
*
* @param triggerName 任务名称
* @param triggerGroupName 传过来的任务名称
* @param time 更新后的时间规则
*/
public void modifyJobTime(String triggerName, String triggerGroupName, String time) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName); //通过触发器名和组名获取TriggerKey
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); //通过TriggerKey获取CronTrigger
if (trigger == null) return;
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(trigger.getCronExpression());
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
trigger = (CronTrigger) trigger.getTriggerBuilder() //重新构建trigger
.withIdentity(triggerKey)
.withSchedule(scheduleBuilder)
.withSchedule(CronScheduleBuilder.cronSchedule(time))
.build();
scheduler.rescheduleJob(triggerKey, trigger); //按新的trigger重新设置job执行
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 移除一个任务(使用默认的任务组名,触发器名,触发器组名)
*
* @param jobName 任务名称
* @param jobGroup 任务组名
*/
public void removeJob(String jobName, String jobGroup) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); //通过触发器名和组名获取TriggerKey
JobKey jobKey = JobKey.jobKey(jobName, jobGroup); //通过任务名和组名获取JobKey
scheduler.pauseTrigger(triggerKey); // 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(jobKey); // 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 移除一个任务
*
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
*/
public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName); //通过触发器名和组名获取TriggerKey
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName); //通过任务名和组名获取JobKey
scheduler.pauseTrigger(triggerKey); // 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(jobKey); // 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 启动所有定时任务
*/
public void startJobs() {
try {
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 关闭所有定时任务
*/
public void shutdownJobs() {
try {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取Trigger
*
* @param jobName 任务名
* @param jobGroup 任务组名
* @return
*/
public Trigger getTrigger(String jobName, String jobGroup) {
try {
TriggerKey key = TriggerKey.triggerKey(jobName, jobGroup);
return scheduler.getTrigger(key);
} catch (SchedulerException e) {
e.printStackTrace();
}
return null;
}
/**
* 暂停任务
*
* @param jobName
* @param jobGroup
*/
public void pauseJob(String jobName, String jobGroup) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 恢复任务
*
* @param jobName
* @param jobGroup
*/
public void resumeJob(String jobName, String jobGroup) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 运行一次
*
* @param jobName
* @param jobGroup
* @param cls
* @param param
*/
public void runone(String jobName, String jobGroup, Class<? extends Job> cls, Map<String, Object> param) {
JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(jobName, jobGroup).build();
jobDetail.getJobDataMap().putAll(param);
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).startNow().build();
try {
if (scheduler.checkExists(trigger.getKey())) {
throw new RuntimeException("任务正在执行请不要重复操作!");
}
scheduler.scheduleJob(jobDetail, trigger);
;
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
感谢参考:[https://blog.csdn.net/qq_42235671/article/details/84642721
]