java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot整合Quartz实现动态配置

SpringBoot整合Quartz实现动态配置的代码示例

作者:失败的面

这篇文章将介绍如何把Quartz定时任务做成接口,实现以下功能的动态配置添加任务,修改任务,暂停任务,恢复任务,删除任务,任务列表,任务详情,文章通过代码示例介绍的非常详细,需要的朋友可以参考下

Spring Boot整合Quartz

简单说下Quartz的整合,做一下准备工作。

导入Quartz依赖

<!--Quartz定时任务-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

配置文件中增加Quartz的支持

spring:
 datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: xxx
    username: xxx
    password: xxx
  quartz:
    job-store-type: jdbc # 定时任务的数据保存到jdbc即数据库中
    jdbc:
      # embedded:默认
      # always:启动的时候初始化表,我们只在第一次启动的时候用它来自动创建表,然后改回embedded即可,不然数据每次都会被清空
      # never:启动的时候不初始化表,也不知道和embedded有什么不同
      initialize-schema: embedded

第一次启动的时候请把上面的initialize-schema设置为always,这会在数据库里面自动建表,然后第二次启动时改回embedded即可。

如果不需要定时任务的持久化就可以不管。

写一个测试用的任务类

import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
@Component
public class QuartzTestJob extends QuartzJobBean {
    @Override
    protected void executeInternal(org.quartz.JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("Quartz Test Job");
    }
}

为这个任务类写一个配置类

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuartzTestJobConfig {
    @Bean
    public JobDetail quartzTestJobDetail() {
        return JobBuilder.newJob(QuartzTestJob.class)
                .withIdentity(QuartzTestJob.class.getSimpleName())
                .storeDurably()
                .usingJobData("data", "test")
                .build();
    }
    @Bean
    public Trigger quartzTestJobTrigger() {
        // 0/1 * * * * ?
        return TriggerBuilder.newTrigger()
                .forJob(QuartzTestJob.class.getSimpleName())
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever())
                .build();
    }
}

结论

以上是使用Quartz写一个定时任务的步骤,很简单,问题是配置写死了,没有办法动态调整,所以我们开始写接口,把上面这个任务配置类去掉。

定时任务动态配置实现

我们还是用上面的任务类QuartzTestJob做测试,这里再说明一次,我们需要有一个任务类作为基础,本文的目的只是去掉上面的QuartzTestJobConfig

剩下的内容没有什么需要多说明的,我直接贴代码了。

业务层

public interface QuartzService {
    /**
     * 添加定时任务
     */
    void addJob(QuartzCreateParam param) throws SchedulerException;
    /**
     * 修改定时任务
     */
    void updateJob(QuartzUpdateParam param) throws SchedulerException;
    /**
     * 暂停定时任务
     */
    void pauseJob(QuartzDetailParam param) throws SchedulerException;
    /**
     * 恢复定时任务
     */
    void resumeJob(QuartzDetailParam param) throws SchedulerException;
    /**
     * 删除定时任务
     */
    void deleteJob(QuartzDetailParam param) throws SchedulerException;
    /**
     * 定时任务列表
     * @return
     */
    List<QuartzJobDetailDto> jobList() throws SchedulerException;
    /**
     * 定时任务详情
     */
    QuartzJobDetailDto jobDetail(QuartzDetailParam param) throws SchedulerException;
}

业务层实现

@Service
public class QuartzServiceImpl implements QuartzService {
    @Autowired
    private Scheduler scheduler;
    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;
    @Override
    public void addJob(QuartzCreateParam param) throws SchedulerException {
        String clazzName = param.getJobClazz();
        String jobName = param.getJobName();
        String jobGroup = param.getJobGroup();
        String cron = param.getCron();
        String description = param.getDescription();
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        checkJobExist(jobKey);
        Class<? extends Job> jobClass = null;
        try {
            jobClass = (Class<? extends Job>) Class.forName(clazzName);
        } catch (ClassNotFoundException e) {
            throw new BaseException("找不到任务类:" + clazzName);
        }
        JobDataMap jobDataMap = new JobDataMap();
        if (param.getJobDataMap() != null) {
            param.getJobDataMap().forEach(jobDataMap::put);
        }
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(jobName, jobGroup)
                .usingJobData(jobDataMap)
                .build();
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
        String triggerId = jobKey.getGroup() + jobKey.getName();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withSchedule(scheduleBuilder)
                .withIdentity(triggerId)
                .withDescription(description)
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        if (!scheduler.isShutdown()) {
            scheduler.start();
        }
    }
    @Override
    public void updateJob(QuartzUpdateParam param) throws SchedulerException {
        String jobName = param.getJobName();
        String jobGroup = param.getJobGroup();
        String cron = param.getCron();
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        String triggerId = jobKey.getGroup() + jobKey.getName();
        checkJobExist(jobKey);
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerId);
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
        TriggerBuilder<?> triggerBuilder = TriggerBuilder.newTrigger()
                .withSchedule(scheduleBuilder)
                .withIdentity(triggerId);
        Trigger trigger = triggerBuilder.build();
        scheduler.rescheduleJob(triggerKey, trigger);
    }
    @Override
    public void pauseJob(QuartzDetailParam param) throws SchedulerException {
        String jobName = param.getJobName();
        String jobGroup = param.getJobGroup();
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        checkJobExist(jobKey);
        scheduler.pauseJob(jobKey);
    }
    @Override
    public void resumeJob(QuartzDetailParam param) throws SchedulerException {
        String jobName = param.getJobName();
        String jobGroup = param.getJobGroup();
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        checkJobExist(jobKey);
        scheduler.resumeJob(jobKey);
    }
    @Override
    public void deleteJob(QuartzDetailParam param) throws SchedulerException {
        String jobName = param.getJobName();
        String jobGroup = param.getJobGroup();
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        checkJobExist(jobKey);
        // 先暂停再删除
        scheduler.pauseJob(jobKey);
        scheduler.deleteJob(jobKey);
    }
    @Override
    public List<QuartzJobDetailDto> jobList() throws SchedulerException {
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        List<QuartzJobDetailDto> jobDtoList = new ArrayList<>();
        for (JobKey jobKey : scheduler.getJobKeys(matcher)) {
            QuartzJobDetailDto jobDto = getJobDtoByJobKey(jobKey);
            jobDtoList.add(jobDto);
        }
        return jobDtoList;
    }
    @Override
    public QuartzJobDetailDto jobDetail(QuartzDetailParam param) throws SchedulerException {
        String jobName = param.getJobName();
        String jobGroup = param.getJobGroup();
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        return getJobDtoByJobKey(jobKey);
    }
    /*************** 私有方法 ***************/
    private void checkJobExist(JobKey jobKey) throws SchedulerException {
        if (!scheduler.checkExists(jobKey)) {
            throw new BaseException("该定时任务不存在:" + jobKey.getName());
        }
    }
    public QuartzJobDetailDto getJobDtoByJobKey(JobKey jobKey) throws SchedulerException {
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        List<Trigger> triggerList = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
        QuartzJobDetailDto jobDto = new QuartzJobDetailDto();
        jobDto.setJobClazz(jobDetail.getJobClass().toString());
        jobDto.setJobName(jobKey.getName());
        jobDto.setJobGroup(jobKey.getGroup());
        jobDto.setJobDataMap(jobDetail.getJobDataMap());
        List<QuartzTriggerDetailDto> triggerDtoList = new ArrayList<>();
        for (Trigger trigger : triggerList) {
            QuartzTriggerDetailDto triggerDto = new QuartzTriggerDetailDto();
            triggerDto.setTriggerName(trigger.getKey().getName());
            triggerDto.setTriggerGroup(trigger.getKey().getGroup());
            triggerDto.setDescription(trigger.getDescription());
            if (trigger instanceof CronTriggerImpl) {
                CronTriggerImpl cronTriggerImpl = (CronTriggerImpl) trigger;
                String cronExpression = cronTriggerImpl.getCronExpression();
                triggerDto.setCron(cronExpression);
                // 最近10次的触发时间
                List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 10);
                triggerDto.setRecentFireTimeList(dates);
            }
            Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
            triggerDto.setTriggerState(triggerState.toString());
            triggerDtoList.add(triggerDto);
        }
        jobDto.setTriggerDetailDtoList(triggerDtoList);
        return jobDto;
    }
}

接口层

@RestController
public class QuartzController {
    @Autowired
    private QuartzServiceImpl quartzService;
    @PostMapping("/quartz/addJob")
    public void addJob(@RequestBody QuartzCreateParam param) throws SchedulerException {
        quartzService.addJob(param);
    }
    @PostMapping("/quartz/updateJob")
    public void updateJob(@RequestBody QuartzUpdateParam param) throws SchedulerException {
        quartzService.updateJob(param);
    }
    @PostMapping("/quartz/pauseJob")
    public void pauseJob(@RequestBody QuartzDetailParam param) throws SchedulerException {
        quartzService.pauseJob(param);
    }
    @PostMapping("/quartz/resumeJob")
    public void resumeJob(@RequestBody QuartzDetailParam param) throws SchedulerException {
        quartzService.resumeJob(param);
    }
    @PostMapping("/quartz/deleteJob")
    public void deleteJob(@RequestBody QuartzDetailParam param) throws SchedulerException {
        quartzService.deleteJob(param);
    }
    @PostMapping("/quartz/jobList")
    public List<QuartzJobDetailDto> jobList() throws SchedulerException {
        return quartzService.jobList();
    }
    @PostMapping("/quartz/jobDetail")
    public QuartzJobDetailDto jobDetail(@RequestBody QuartzDetailParam param) throws SchedulerException {
        return quartzService.jobDetail(param);
    }
}

接口请求参数

@ApiModel(value = "Quartz任务添加请求参数")
public class QuartzCreateParam extends BaseParam {
    @NotBlank(message = "任务类不能为空")
    @ApiModelProperty(value = "任务类路径", required = true)
    private String jobClazz;
    @NotBlank(message = "任务类名不能为空")
    @ApiModelProperty(value = "任务类名", required = true)
    private String jobName;
    /**
     * 组名+任务类key组成唯一标识,所以如果这个参数为空,那么默认以任务类key作为组名
     */
    @ApiModelProperty(value = "任务组名,命名空间")
    private String jobGroup;
    @ApiModelProperty(value = "任务数据")
    private Map<String, Object> jobDataMap;
    @ApiModelProperty(value = "cron表达式")
    private String cron;
    @ApiModelProperty(value = "描述")
    private String description;
}
@ApiModel(value = "Quartz任务更新请求参数")
public class QuartzUpdateParam extends BaseParam {
    @NotBlank(message = "任务类名不能为空")
    @ApiModelProperty(value = "任务类名", required = true)
    private String jobName;
    @ApiModelProperty(value = "任务组名,命名空间")
    private String jobGroup;
    @ApiModelProperty(value = "cron表达式")
    private String cron;
}
@ApiModel(value = "Quartz任务详情请求参数")
public class QuartzDetailParam extends BaseParam {
    @NotBlank(message = "任务类名不能为空")
    @ApiModelProperty(value = "任务类名", required = true)
    private String jobName;
    @ApiModelProperty(value = "任务组名,命名空间")
    private String jobGroup;
}

接口返回结果类

@ApiModel(value = "Quartz定时任务详情类")
public class QuartzJobDetailDto {
    @ApiModelProperty(value = "任务类路径")
    private String jobClazz;
    @ApiModelProperty(value = "任务类名")
    private String jobName;
    @ApiModelProperty(value = "任务组名,命名空间")
    private String jobGroup;
    @ApiModelProperty(value = "任务数据")
    private Map<String, Object> jobDataMap;
    @ApiModelProperty(value = "触发器列表")
    private List<QuartzTriggerDetailDto> triggerDetailDtoList;
}
@ApiModel(value = "Quartz定时任务触发器详情类")
public class QuartzTriggerDetailDto {
    private String triggerName;
    private String triggerGroup;
    private String cron;
    private String description;
    private String triggerState;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private List<Date> recentFireTimeList;
}

调用接口进行测试

写完接口代码后,我们来测试一下

添加任务接口:/quartz/addJob

{
    "jobClazz": "com.cc.job.QuartzTestJob",
    "jobName": "QuartzTestJob",
    "cron": "1/2 * * * * ? ",
    "description": "测试定时任务",
    "jobDataMap": {
        "key": "value"
    }
}

修改任务接口:/quartz/updateJob

{
    "jobName": "QuartzTestJob",
    "cron": "0/2 * * * * ?"
}

修改任务只能修改cron时间,如果想要修改其他内容,只能删除任务后重新添加。

删除任务接口:/quartz/updateJob

{
    "jobName": "QuartzTestJob"
}

暂停、恢复、详情接口同删除任务接口的请求参数,就不赘述了。

任务列表:/quartz/jobList

{}

返回结果:

{
    "code": 10000,
    "msg": "请求成功",
    "data": [
        {
            "jobClazz": "class com.cc.job.QuartzTestJob",
            "jobName": "QuartzTestJob",
            "jobGroup": "DEFAULT",
            "jobDataMap": {
                "key": "value"
            },
            "triggerDetailDtoList": [
                {
                    "triggerName": "DEFAULTQuartzTestJob",
                    "triggerGroup": "DEFAULT",
                    "cron": "0/2 * * * * ?",
                    "description": null,
                    "triggerState": "NORMAL",
                    "recentFireTimeList": [
                        "2023-07-19 09:23:16",
                        "2023-07-19 09:23:18",
                        "2023-07-19 09:23:20",
                        "2023-07-19 09:23:22",
                        "2023-07-19 09:23:24",
                        "2023-07-19 09:23:26",
                        "2023-07-19 09:23:28",
                        "2023-07-19 09:23:30",
                        "2023-07-19 09:23:32",
                        "2023-07-19 09:23:34"
                    ]
                }
            ]
        }
    ],
    "traceId": null,
    "success": true
}

以上就是SpringBoot整合Quartz实现动态配置的详细内容,更多关于Spring Boot整合Quartz实现动态配置的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文