SpringBoot实现quartz定时任务可视化管理功能

前言

在实际框架或产品开发过程中,springboot中集成quarzt方式基本是以job和trigger的bean对象方式直接硬编码完成的,例如以下代码示例。对于系统内定义的所有定时任务类型,具体执行类,执行策略,运行状态都没有一个动态全局的管理,所有决定将quartz做成可视化配置管理,便于统一管理,也降低了使用门槛,只需要关心job类的实现即可

@Bean
public JobDetail SMSJobDetail() {
return JobBuilder.newJob(SMSJob.class).withIdentity("SMSJob").storeDurably().build();
}

// 把jobDetail注册到trigger上去
@Bean
public Trigger myJobTrigger() {
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1).repeatForever();

return TriggerBuilder.newTrigger()
.forJob(SMSJobDetail())
.withIdentity("myJobTrigger")
.withSchedule(scheduleBuilder)
.build();
}

表结构

用于存储quartz配置

DROP TABLE IF EXISTS `f_quartztask`;
CREATE TABLE `f_quartztask` (
`TaskID` varchar(50) NOT NULL,
`TaskName` varchar(200) DEFAULT NULL,
`TaskType`int(11) DEFAULT NULL,
`TaskTag` varchar(100) DEFAULT NULL,
`JobClassPath` varchar(200) DEFAULT NULL,
`ExecutePeroid`int(11) DEFAULT NULL,
`ExecuteUnit`int(11) DEFAULT NULL,
`CornExpress` varchar(200) DEFAULT NULL,
`Enviroment` varchar(50) DEFAULT NULL,
`TaskStatus`int(11) DEFAULT NULL,
`SortNum`int(11) DEFAULT NULL,
`Remark` varchar(500) DEFAULT NULL,
PRIMARY KEY (`TaskID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

枚举类

public class QuartzEnum {
public enum TaskTypeimplements IConvertEnumToCodeItem {
Cycle(10,"循环任务"), Corn(20,"Corn表达式任务");
private int _value;
private String _name;

private TaskType(int value, String name) {
set_value(value);
set_name((name));
}

public int get_value() {
return _value;
}

public void set_value(int _value) {
this._value = _value;
}

public String get_name() {
return _name;
}

public void set_name(String _name) {
this._name = _name;
}

@Override
public String toString() {
return _name;
}

@Override
public String getCodeName() {
return "Quartz任务类别";
}
}

public enum ExecuteUnitimplements IConvertEnumToCodeItem {
Second(10,"秒"), Minute(20,"分"), Hour(30,"时");
private int _value;
private String _name;

private ExecuteUnit(int value, String name) {
set_value(value);
set_name((name));
}

public int get_value() {
return _value;
}

public void set_value(int _value) {
this._value = _value;
}

public String get_name() {
return _name;
}

public void set_name(String _name) {
this._name = _name;
}

@Override
public String toString() {
return _name;
}

@Override
public String getCodeName() {
return "Quartz间隔单位";
}
}


public enum TaskStatusimplements IConvertEnumToCodeItem {
Open(10,"开启"), Close(20,"关闭");
private int _value;
private String _name;

private TaskStatus(int value, String name) {
set_value(value);
set_name((name));
}

public int get_value() {
return _value;
}

public void set_value(int _value) {
this._value = _value;
}

public String get_name() {
return _name;
}

public void set_name(String _name) {
this._name = _name;
}

@Override
public String toString() {
return _name;
}

@Override
public String getCodeName() {
return "Quartz任务状态";
}
}

public enum TaskEnviromentimplements IConvertEnumToCodeItem {
All("全部","全部"), Dev("dev","开发环境"), Pro("pro","正式环境");
private String _value;
private String _name;

private TaskEnviroment(String value, String name) {
set_value(value);
set_name((name));
}

public String get_value() {
return _value;
}

public void set_value(String _value) {
this._value = _value;
}

public String get_name() {
return _name;
}

public void set_name(String _name) {
this._name = _name;
}

@Override
public String toString() {
return _name;
}

@Override
public String getCodeName() {
return "Quartz任务执行环境";
}
}
}

QuartzFactory

支持Job类注bean入对象

@Component
public class QuartzFactoryextends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;

@Override
protected Object createJobInstance(TriggerFiredBundle bundle)throws Exception {
// 调用父类的方法
Object jobInstance =super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;

}
}

QuartzConfig

注入QuartzFactory对象

@Configuration
public class QuartzConfig {
@Autowired
private QuartzFactory quartzFactory;

@Bean
public SchedulerFactoryBean schedulerFactoryBean(){
SchedulerFactoryBean schedulerFactoryBean =new SchedulerFactoryBean();
schedulerFactoryBean.setJobFactory(quartzFactory);
//将job实例化,能够操作进行Spring 注入
return schedulerFactoryBean;
}
}

QuartzUtil

定时任务动态添加/删除操作类,initQuartzTask方法在系统启动时执行,根据配置自动开启相关符合条件的任务

@Component
public class QuartzUtil {
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
@Autowired
private F_QuartzTaskService quartzTaskService;
@Value("${spring.profiles.active}")
private String active;
private static String JOB_GROUP_NAME ="DEFAULT_JOB_GROUP_NAME";
private static String TRIGGER_GROUP_NAME ="DEFAULT_TRIGGER_GROUP_NAME";


public void initQuartzTask() {
List<F_QuartzTaskDO> openTaskList = quartzTaskService.selectAllList();
if(openTaskList.size()>0){
openTaskList = openTaskList.stream().filter(a -> a.getTaskStatus() == QuartzEnum.TaskStatus.Open.get_value() &&
(a.getEnviroment().equals(QuartzEnum.TaskEnviroment.All.get_name()) || a.getEnviroment().equals(active))).collect(Collectors.toList());
}
for (F_QuartzTaskDO taskDO : openTaskList) {
try {
Class<Job> jobClass = (Class<Job>) Class.forName(taskDO.getJobClassPath());
if (taskDO.getTaskType() == QuartzEnum.TaskType.Cycle.get_value()) {
addIntervalJob(taskDO.getTaskTag(), jobClass, taskDO.getExecutePeroid(), taskDO.getExecuteUnit());
}else {
addCornJob(taskDO.getTaskTag(), jobClass, taskDO.getCornExpress());
}
}catch (Exception e) {
e.printStackTrace();
}
}
if (openTaskList.size() >0) {
System.out.println("扫描并初始化开启quartz定时任务成功,任务数量:" + openTaskList.size() +"个");
}
}

public void startTask( F_QuartzTaskDO taskDO){
try {
Class<Job> jobClass = (Class<Job>) Class.forName(taskDO.getJobClassPath());
if (taskDO.getTaskType() == QuartzEnum.TaskType.Cycle.get_value()) {
addIntervalJob(taskDO.getTaskTag(), jobClass, taskDO.getExecutePeroid(), taskDO.getExecuteUnit());
}else {
addCornJob(taskDO.getTaskTag(), jobClass, taskDO.getCornExpress());
}
}catch (Exception e) {
e.printStackTrace();
}
}

//增加定时任务任务
public void addIntervalJob(String jobName, Class<?extends Job> cls,int peroid,int timeUnit) {
try {
SimpleScheduleBuilder scheduleBuilder =null;
if (timeUnit == QuartzEnum.ExecuteUnit.Second.get_value()) {
scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(peroid).repeatForever();
}else if (timeUnit == QuartzEnum.ExecuteUnit.Minute.get_value()) {
scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInMinutes(peroid).repeatForever();
}else if (timeUnit == QuartzEnum.ExecuteUnit.Hour.get_value()) {
scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(peroid).repeatForever();
}
Scheduler sched = schedulerFactoryBean.getScheduler();
JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(jobName, JOB_GROUP_NAME).storeDurably().build();
Trigger trigger = TriggerBuilder.newTrigger().forJob(jobDetail).withIdentity(jobName, TRIGGER_GROUP_NAME).withSchedule(scheduleBuilder).build();

sched.scheduleJob(jobDetail, trigger);
if (!sched.isShutdown()) {
sched.start(); // 启动
}
}catch (Exception e) {
throw new RuntimeException(e);
}
}

//增加corn表达式任务
public void addCornJob(String jobName, Class<?extends Job> cls, String cornExpress) {
try {
Scheduler sched = schedulerFactoryBean.getScheduler();
JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(jobName, JOB_GROUP_NAME).build();
CronTrigger trigger = (CronTrigger) TriggerBuilder
.newTrigger()
.withIdentity(jobName, TRIGGER_GROUP_NAME)
.withSchedule(CronScheduleBuilder.cronSchedule(cornExpress))
.build();
sched.scheduleJob(jobDetail, trigger);
if (!sched.isShutdown()) {
sched.start(); // 启动
}
}catch (Exception e) {
throw new RuntimeException(e);
}
}

//停止任务
public void deleteJob(String jobName) {
try {
Scheduler sched = schedulerFactoryBean.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME);
JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME);
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(jobKey); // 删除任务
}catch (Exception e) {
throw new RuntimeException(e);
}
}

}

界面展示



推荐 收藏
评论(0) 阅读(338)
刷新评论 返回顶部
Caesar最新博客