实现效果: 动态添加, 删除, 更新定时任务
实现方案:
1. 配置类
QuartzConfig.java
package com.hejjon.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.io.IOException;
/**
* Created by caoshi at 21:53 2022-05-23
*/
@Configuration
public class QuartzConfig {
@Autowired
@Qualifier(value = "taskExecutor")
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Bean("MySchedulerFactoryBean")
@Order(2)
public SchedulerFactoryBean getSchedulerFactoryBean() throws IOException {
if(threadPoolTaskExecutor == null){
//logger.error("threadPoolTaskExecutor is null");
System.exit(0);
}
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("application.properties"));
//在quartz.properties中的属性被读取并注入后再初始化对象
propertiesFactoryBean.afterPropertiesSet();
//创建SchedulerFactoryBean
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setTaskExecutor(threadPoolTaskExecutor);
factory.setQuartzProperties(propertiesFactoryBean.getObject());
//这样当spring关闭时,会等待所有已经启动的quartz job结束后spring才能完全shutdown。
factory.setWaitForJobsToCompleteOnShutdown(true);
factory.setOverwriteExistingJobs(false);
factory.setStartupDelay(1);
return factory;
}
}
ThreadPoolConfig.java
package com.hejjon.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.RejectedExecutionHandler;
/**
* Created by caoshi at 23:22 2022-05-23
*/
@Configuration
public class ThreadPoolConfig {
@Bean("taskExecutor")
@Primary
public ThreadPoolTaskExecutor getThreadPoolTaskExecutor(){
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setMaxPoolSize(5);
threadPoolTaskExecutor.setCorePoolSize(2);
RejectedExecutionHandler handler = (r, executor) -> {
//logger.error("线程池超过最大容量,进行扩容 {} ",executor.getPoolSize());
executor.setMaximumPoolSize(10);
Thread thread = new Thread(r);
thread.start();
//logger.error(r.toString());
};
threadPoolTaskExecutor.setRejectedExecutionHandler(handler);
return threadPoolTaskExecutor;
}
}
2. 任务实体
QuartzTask.java
package com.hejjon.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* Created by caoshi at 22:17 2022-05-23
*/
@Data
@TableName("quartz_task")
public class QuartzTask implements Serializable {
private static final long serialVersionUID = -848456746691499366L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 类型
*/
@TableField("type")
private String type;
/**
* 任务所在任务组名称
*/
@TableField("jobGroup")
private String jobGroup;
/**
* 任务名称
*/
@TableField("jobName")
private String jobName;
/**
* 执行定时任务参数
*/
@TableField("invokeParam")
private String invokeParam;
/**
* 定时任务执行表达式
*/
@TableField("cron")
private String cron;
/**
* 任务状态
*/
@TableField("status")
private String status;
/**
* 执行任务最近时间
*/
@TableField("executeEndtime")
private Date executeEndtime;
}
3. 定时任务管理器
QuartzJobManager.java
package com.hejjon.manager;
import com.hejjon.entity.QuartzTask;
import com.hejjon.service.ScheduledJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
/**
* Created by caoshi at 22:01 2022-05-23
*/
@Component
public class QuartzJobManager {
@Autowired
@Qualifier("MySchedulerFactoryBean")
private SchedulerFactoryBean schedulerFactoryBean;
/**
* 创建定时任务
*/
public void insertJob(QuartzTask task) throws SchedulerException {
Long taskId = task.getId();
// 获取调度器
Scheduler scheduler = schedulerFactoryBean.getScheduler();
// 执行任务的具体 ScheduledJob 类实现Job接口, 重写execute 方法.
// 该方法内容是执行定时任务的核心业务
JobDetail jobDetail = JobBuilder.newJob(ScheduledJob.class)
.withIdentity("job" + taskId, "group1")
.build();
// cron表达式构建器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCron());
// 触发器
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("job" + taskId, "group1")
.withSchedule(cronScheduleBuilder)
.build();
trigger.getJobDataMap().put("taskId", taskId);
// 交给调度器管理
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 删除定时任务
* @param jobName
* @param groupName
* @throws SchedulerException
*/
public void deleteJob(String jobName, String groupName) throws SchedulerException {
// 获取调度器
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduler.deleteJob(JobKey.jobKey(jobName, groupName));
}
/**
* 更新定时任务
* 更新的逻辑是先删除旧的再新增新的
* @param oldJobName
* @param oldGroupName
* @param newTask
* @throws SchedulerException
*/
public void updateJob(String oldJobName, String oldGroupName, QuartzTask newTask) throws SchedulerException {
// 先删除再增加一个新的任务
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(oldJobName, oldGroupName);
boolean exists = scheduler.checkExists(jobKey);
if (exists) {
scheduler.deleteJob(jobKey);
}
insertJob(newTask);
}
}
测试:
package com.hejjon.controller;
import com.alibaba.fastjson.JSON;
import com.hejjon.entity.QuartzTask;
import com.hejjon.manager.QuartzJobManager;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by caoshi at 22:55 2022-05-23
*/
@RestController
@RequestMapping("/test")
public class TestController {
private QuartzJobManager quartzJobManager;
@Autowired
public void setQuartzJobManager(QuartzJobManager quartzJobManager) {
this.quartzJobManager = quartzJobManager;
}
@RequestMapping("/addTimerTask")
public String addTimerTask(@RequestBody QuartzTask task) {
try {
quartzJobManager.insertJob(task);
} catch (SchedulerException e) {
e.printStackTrace();
}
return "添加定时任务成功";
}
}