功能点
- 添加CRON、固定间隔定时
- 修改定时的触发器
- 修改定时参数
- 暂停定时
- 启动暂停的定时
- 获取所有定时
- 启动所有定时
- 停止定时
0.通过maven引入jar包
<!-- 定时任务 quartz配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
1. 定时类型
Quartz可以通过org.quartz.Trigger.class去拓展定时类型的,目前需求需要支持CRON和固定间隔两种定时类型,后期需要支持跳过节假日、周一~周五、周末等需求,所以需要让定时类型支持拓展。
1.1定时类型
/**
*
* 定时类型触发器类型
* @author jiangwei
*
*/
public enum TriggerType {
/**
* 标准CRON支持
*/
CRON("标准CRON支持"),
/**
* 固定间隔毫秒
*/
INTERVAL_MILLISECOND("固定间隔毫秒"),
/**
* 固定间隔秒
*/
INTERVAL_SECOND("固定间隔秒"),
/**
* 固定间隔分钟
*/
INTERVAL_MINUTE("固定间隔分钟"),
/**
* 固定间隔小时
*/
INTERVAL_HOUR("固定间隔小时"),
/**
* 工作日,跳过节假日
*/
WEEKDAYS("工作日,跳过节假日"),
/**
* 节假日
*/
HOLIDAY("节假日")
;
private String describe;
TriggerType(String describe) {
this.describe = describe;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
}
1.2 构建定时任务的抽象类
我们需要构建不同的定时类型,不同的定时类型需要的参数也是不同的,因此我们需要抽象出定时的公用参数,将不同的参数多态实现
/**
* 构建定时任务基础对象
* @author jiangwei
*
*/
public class TaskInfo {
/**
* 该定时的任务处理器
*/
private Class<? extends QuartzTaskJob> taskClass;
/**
* 任务名
*/
private String taskName;
/**
* 任务组名
* */
private String groupName;
/**
* 任务描述
* */
private String description;
/**
* 任务类型
*/
private TriggerType type;
/**
* 任务参数,可在具体的QuartzTaskJob实现中获取这些参数
* */
private Map<String, Object> param;
/**
* 任务状态
* */
private String taskStatus;
public TaskInfo(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type, Map<String, Object> param) {
this.taskClass = taskClass;
this.taskName = taskName;
this.groupName = groupName;
this.description = description;
this.type = type;
this.param = param;
}
public TaskInfo(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type) {
this.taskClass = taskClass;
this.taskName = taskName;
this.groupName = groupName;
this.description = description;
this.type = type;
}
public Class<? extends QuartzTaskJob> getTaskClass() {
return taskClass;
}
public void setTaskClass(Class<? extends QuartzTaskJob> taskClass) {
this.taskClass = taskClass;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public TriggerType getType() {
return type;
}
public void setType(TriggerType type) {
this.type = type;
}
public Map<String, Object> getParam() {
return param;
}
public void setParam(Map<String, Object> param) {
this.param = param;
}
public String getTaskStatus() {
return taskStatus;
}
public void setTaskStatus(String taskStatus) {
this.taskStatus = taskStatus;
}
}
1.3 用以构建CRON定时任务
/**
* 用以构建CRON定时任务
* cron触发器
* @author jiangwei
*
*/
public class CronInfo extends TaskInfo{
/**
* cron表达式
* */
private String cronExpression;
public CronInfo(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description,
Map<String, Object> param,String cronExpression) {
super(taskClass, taskName, groupName, description, TriggerType.CRON, param);
this.cronExpression = cronExpression;
}
public CronInfo(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName,
String description,String cronExpression) {
super(taskClass, taskName, groupName, description, TriggerType.CRON);
this.cronExpression = cronExpression;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
}
1.4 用以构建固定间隔定时任务
/**
* 用以构建固定间隔定时任务
* @author jiangwei
*
*/
public class IntervalInfo extends TaskInfo{
/**
* 事件间隔,根据TriggerType确定单位,除了数值为毫秒,该数值必须在-2^32~2^31 (-2147483648 ~ 2147483647)
* */
private Long interval;
/**
* 重复次数,会执行该数值+1次,为空无限重复
* */
private Integer repeatCount;
public IntervalInfo(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description,
TriggerType type, Map<String, Object> param, Long interval,Integer repeatCount) {
super(taskClass, taskName, groupName, description, type, param);
if (type != TriggerType.INTERVAL_MILLISECOND){
if (interval<(-2^32)||interval>(2^31)){
throw new TaskException("interval超出范围,除了类型为INTERVAL_MILLISECOND的数据间隔定时的interval范围必须在-2^32~2^31 (-2147483648 ~ 2147483647)");
}
}
this.interval = interval;
this.repeatCount = repeatCount;
}
public IntervalInfo(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type, Long interval,Integer repeatCount) {
super(taskClass, taskName, groupName, description, type);
if (type != TriggerType.INTERVAL_MILLISECOND){
if (interval<(-2^32)||interval>(2^31)){
throw new TaskException("interval超出范围,除了类型为INTERVAL_MILLISECOND的数据间隔定时的interval范围必须在-2^32~2^31 (-2147483648 ~ 2147483647)");
}
}
this.interval = interval;
this.repeatCount = repeatCount;
}
public Long getInterval() {
return interval;
}
public void setInterval(Long interval) {
this.interval = interval;
}
public Integer getRepeatCount() {
return repeatCount;
}
public void setRepeatCount(Integer repeatCount) {
this.repeatCount = repeatCount;
}
}
2.抽象任务类
/**
* 抽象任务类
* @author jiangwei
*
*/
public interface QuartzTaskJob extends Job{
/**
* 执行定时任务
*/
@Override
void execute(JobExecutionContext context) throws JobExecutionException;
}
2.1 实现一个测试任务
/**
* 实现一个测试任务
* @author jiangwei
*
*/
@Component
public class TestQuartz implements QuartzTaskJob{
private Logger log=LoggerFactory.getLogger(TestQuartz.class);
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 获取参数
JobDataMap jobDataMap = context.getTrigger().getJobDataMap();
// 获取任务名
String name = context.getJobDetail().getJobBuilder().build().getKey().getName();
// 获取任务分组
String group = context.getJobDetail().getJobBuilder().build().getKey().getGroup();
// 获取任务描述
String description = context.getJobDetail().getDescription();
if (context.getTrigger() instanceof SimpleTrigger){
// 运行次数
System.out.println(((SimpleTrigger)context.getTrigger()).getTimesTriggered());
}
log.info("----------------------" +
"\n任务组:{}\n任务名:{}\n任务描述:{}\n获取参数paramKey:{}\n" +
"----------------------"
,name,group,description,jobDataMap.getString("paramKey"));
try {
// QuartzJobManager.getInstance().jobdelete(this.getClass().getSimpleName(),"ah");//执行完此任务就删除自己
} catch (Exception e) {
e.printStackTrace();
}
}
}
3. 构建触发器的不同实现
3.1 抽象触发器实现
/**
* 触发器工厂
*
* @author jiangwei
*
*/
public interface ITriggerFactory {
/**
* 判断是否为该类型的触发器
*
* @param triggerType 触发器类型
* @return boolean 如果是该类型的触发器返回true 否则返回false
*/
public boolean check(TriggerType triggerType);
/**
* 创建触发器
* @param taskInfo:定时任务基础信息
* @return Trigger
*/
public Trigger build(TaskInfo taskInfo);
}
3.2 CRON触发器
/**
*
* CRON触发器
*
* @author jiangwei
*
*/
@Component
public class CronTrigger implements ITriggerFactory{
@Override
public boolean check(TriggerType triggerType) {
return triggerType==TriggerType.CRON;
}
@Override
public Trigger build(TaskInfo taskInfo) {
if (!(taskInfo instanceof CronInfo)){
throw new TaskException("构建类型为CRON定时必须传入CronTimingModel.class的实现类");
}
//按新的cronExpression表达式构建一个新的trigger
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(((CronInfo) taskInfo).getCronExpression());
return TriggerBuilder.newTrigger().withIdentity(taskInfo.getTaskName(), taskInfo.getTaskName())
.withSchedule(scheduleBuilder).build();
}
}
3.3 固定间隔触发器
/**
*
* 固定间隔触发器
*
* @author jiangwei
*
*/
@Component
public class IntervalTrigger implements ITriggerFactory{
@Override
public boolean check(TriggerType triggerType) {
return triggerType == TriggerType.INTERVAL_MINUTE || triggerType == TriggerType.INTERVAL_SECOND || triggerType == TriggerType.INTERVAL_MILLISECOND||triggerType == TriggerType.INTERVAL_HOUR;
}
@Override
public Trigger build(TaskInfo taskInfo) {
if (!(taskInfo instanceof IntervalInfo)){
throw new TaskException("构建类型为INTERVAL定时必须传入IntervalTimingMode.class的实现类");
}
//创建触发器
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
Long interval = ((IntervalInfo) taskInfo).getInterval();
Integer repeatCount = ((IntervalInfo) taskInfo).getRepeatCount();
switch (taskInfo.getType()){
case INTERVAL_MINUTE:
simpleScheduleBuilder.withIntervalInMinutes(Math.toIntExact(interval));
break;
case INTERVAL_HOUR:
simpleScheduleBuilder.withIntervalInHours(Math.toIntExact(interval));
break;
case INTERVAL_SECOND:
simpleScheduleBuilder.withIntervalInSeconds(Math.toIntExact(interval));
break;
case INTERVAL_MILLISECOND:
simpleScheduleBuilder.withIntervalInMilliseconds(interval);
break;
default:
break;
}
if (repeatCount==null){
// 无限重复
simpleScheduleBuilder.repeatForever();
}else {
simpleScheduleBuilder.withRepeatCount(repeatCount);
}
return TriggerBuilder.newTrigger().withIdentity(taskInfo.getTaskName(), taskInfo.getTaskName())
.withSchedule(simpleScheduleBuilder).build();
}
}
3.4 构建触发器工厂
/**
*
* 构建触发器工厂
* 触发器管理器, 用来生成触发器
*
* @author jiangwei
*
*/
@Component
public class TriggerManager {
private final List<ITriggerFactory> triggerFactories;
public TriggerManager(List<ITriggerFactory> triggerFactories) {
this.triggerFactories = triggerFactories;
}
/**
* 生成对应的触发器
*
* @param timingModel 触发器model
* @return org.quartz.Trigger
* @author YuanXiaohan
* @date 2021/12/16 2:53 下午
*/
public Trigger build(TaskInfo taskInfo) {
for (ITriggerFactory triggerFactory : triggerFactories) {
if (triggerFactory.check(taskInfo.getType())) {
return triggerFactory.build(taskInfo);
}
}
return null;
}
}
3. 构建定时管理类
/**
* 构建定时管理类
*
* 添加定时
* 更新定时触发器
* 更新任务参数
* 删除任务
* 暂停任务
* 将暂停的任务恢复执行
* 启动所有任务
* 关闭定时任务
* 获取所有任务
* @author jiangwei
*
*/
@Configuration
public class QuartzTaskManager {
private Logger log=LoggerFactory.getLogger(QuartzTaskManager.class);
private final Scheduler scheduler;
private final Boolean initStatus;
private final TriggerManager triggerManager;
private static QuartzTaskManager taskManager;
public QuartzTaskManager(Scheduler scheduler, TriggerManager triggerManager) {
this.scheduler = scheduler;
taskManager = this;
boolean status = true;
try {
// 启动调度器
scheduler.start();
} catch (SchedulerException e) {
log.error("定时器调度器启动失败,定时器不可用!", e);
status = false;
}
initStatus = status;
this.triggerManager = triggerManager;
}
public static QuartzTaskManager getInstance(){
return taskManager;
}
/**
* 添加定时任务
*
* @param timingModel 任务model
*/
public void addTask(TaskInfo taskInfo) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
InstantiationException, SchedulerException {
checkTimingInit();
// 构建任务信息
JobDetail jobDetail = JobBuilder.newJob(taskInfo.getTaskClass().getDeclaredConstructor().newInstance().getClass())
.withDescription(taskInfo.getDescription())
.withIdentity(taskInfo.getTaskName(), taskInfo.getGroupName())
.build();
// 构建触发器
Trigger trigger = triggerManager.build(taskInfo);
// 将任务参数放入触发器中
if (taskInfo.getParam() != null && !taskInfo.getParam().isEmpty()) {
trigger.getJobDataMap().putAll(taskInfo.getParam());
}
// 启动任务
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 更新任务,任务的标示(由taskName和groupName组成)不变,任务的触发器(触发频率)发生变化
*
* @param timingModel 任务model
*/
public void updateTask(TaskInfo taskInfo) throws SchedulerException {
// 获取到任务
TriggerKey triggerKey = TriggerKey.triggerKey(taskInfo.getTaskName(), taskInfo.getGroupName());
// 构建触发器
Trigger trigger = triggerManager.build(taskInfo);
// 将任务参数放入触发器中
if (taskInfo.getParam() != null && !taskInfo.getParam().isEmpty()) {
trigger.getJobDataMap().putAll(taskInfo.getParam());
}
// 将新的触发器绑定到任务标示上重新执行
scheduler.rescheduleJob(triggerKey, trigger);
}
/**
* 更新任务参数
*
* @param taskName 任务名
* @param groupName 任务组名
* @param param 参数
*/
public void updateTask(String taskName, String groupName, Map<String, Object> param) throws SchedulerException {
// 获取到任务
TriggerKey triggerKey = TriggerKey.triggerKey(taskName, groupName);
Trigger trigger = scheduler.getTrigger(triggerKey);
//修改参数
trigger.getJobDataMap().putAll(param);
// 将新的触发器绑定到任务标示上重新执行
scheduler.rescheduleJob(triggerKey, trigger);
}
/**
* 删除任务
*
* @param taskName 任务名
* @param groupName 任务组
*/
public void deleteTask(String taskName, String groupName) throws SchedulerException {
// 暂停任务对应的触发器
scheduler.pauseTrigger(TriggerKey.triggerKey(taskName, groupName));
// 删除任务对应的触发器
scheduler.unscheduleJob(TriggerKey.triggerKey(taskName, groupName));
// 删除任务
scheduler.deleteJob(JobKey.jobKey(taskName, groupName));
}
/**
* 暂停任务
*
* @param taskName 添加任务时timingMode中的taskName
* @param groupName 添加任务时timingMode中的groupName
*/
public void pauseTask(String taskName, String groupName) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(taskName, groupName));
}
/**
* 将暂停的任务恢复执行
*
* @param taskName 添加任务时timingMode中的taskName
* @param groupName 添加任务时timingMode中的groupName
*/
public void resumeTask(String taskName, String groupName) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(taskName, groupName));
}
/**
* 启动所有任务
*
*/
public void startAllTasks() {
try {
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 关闭定时任务,回收所有的触发器资源
*
*/
public void shutdownAllTasks() {
try {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取所有的任务,暂时无法获取到任务执行类和任务描述
*
* @return java.util.List<org.demo.quartz.mode.TimingModel>
* @author YuanXiaohan
* @date 2021/12/16 3:37 下午
*/
public List<TaskInfo> getTaskList() throws SchedulerException {
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
List<TaskInfo> taskList = new ArrayList<TaskInfo>();
for (JobKey jobKey : jobKeys) {
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
for (Trigger trigger : triggers) {
TaskInfo taskInfo;
if (trigger instanceof CronTrigger) {
taskInfo = new CronInfo(null, jobKey.getName(), jobKey.getGroup(), null, ((CronTrigger) trigger).getCronExpression());
taskInfo.setTaskStatus(scheduler.getTriggerState(trigger.getKey()).name());
taskList.add(taskInfo);
} else {
log.warn("name:{},group:{}的定时任务类型未知,请拓展QuartzTaskManager.getTaskList的任务类型解析", jobKey.getName(), jobKey.getGroup());
}
}
}
return taskList;
}
/**
* 校验定时调度器是否初始化完成
*/
private void checkTimingInit() {
if (!initStatus) {
throw new TaskException("定时器未初始化,添加定时器失败!");
}
}
}
4. Quartz注入到SpringBoot
/**
* Quartz注入到SpringBoot
* @author jiangwei
*
*/
@Component
public class TaskJobFactory extends AdaptableJobFactory{
private final AutowireCapableBeanFactory capableBeanFactory;
public TaskJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
this.capableBeanFactory = capableBeanFactory;
}
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
5. 执行
public class JwbastaThymeleafAdminApplicaiton implements CommandLineRunner{
private static Logger logger=LoggerFactory.getLogger(JwbastaThymeleafAdminApplicaiton.class);
public static void main(String[] args) {
SpringApplication.run(JwbastaThymeleafAdminApplicaiton.class, args);
}
}
@Override
public void run(String... args) throws Exception {
//构建CRON定时
//CronTimingModel cronTimingModel = new CronTimingModel(TestQuartz.class, "测试名", "测试组", "测试描述", "*/1 * * * * ?");
// 构建固定间隔定时
IntervalInfo intervalTimingMode = new IntervalInfo(TestQuartz.class, "测试名", "测试组", "测试描述", TriggerType.INTERVAL_SECOND, 5L,null);
HashMap<String, Object> param = new HashMap<>();
param.put("paramKey","获取到参数了");
intervalTimingMode.setParam(param);
QuartzTaskManager.getInstance().addTask(intervalTimingMode);
}
}
jwbasta官网
|