SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作
  19qMgiCiiRfc 2023年12月05日 23 0

一、前言

Quartz是一个非常好的定时任务框架,它的轻量级、高可靠性、易于使用的特点,使得它成为一个非常受欢迎的任务框架。这篇文章中我们将介绍如何使用SpringBoot整合Quartz并将定时任务写入数据库中,并对定时任务进行如启动、删除、暂停、恢复等操作。

二、整合Quartz

1.添加相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>HelloDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>HelloDemo</name>
    <description>HelloDemo</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <image>
                        <builder>paketobuildpacks/builder-jammy-base:latest</builder>
                    </image>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2.编写相关配置

我们在application.properties文件中进行数据库的配置和Quartz的配置。

#数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/shop?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true

#quartz配置
# 数据存储方式 数据库的方式
spring.quartz.job-store-type=jdbc
# 调度标识名
spring.quartz.properties.org.quartz.scheduler.instanceName=clusteredScheduler
# ID设置为自动获取
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
#数据保存方式为持久化
spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库平台
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#表的前缀
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
#是否加入集群
spring.quartz.properties.org.quartz.jobStore.isClustered=false
#调度实例失效的检查时间间隔
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=10000
#设置为True不会出现序列化非字符串到BLOB时产生的类版本问题
spring.quartz.properties.org.quartz.jobStore.useProperties=false
#ThreadPool实现的类名
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
#线程数量
spring.quartz.properties.org.quartz.threadPool.threadCount=5
#线程优先级
spring.quartz.properties.org.quartz.threadPool.threadPriority=5
#自创建父线程
spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true

3.添加Quartz表

我们在使用quartz做持久化的时候需要用到quartz的11张表,我们可以去quartz的官网下载对应版本的quartz.地址:http://www.quartz-scheduler.org/downloads/

下载之后解压找到对应版本的sql文件,并选择innodb引擎的版本。


SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_Quartz

我们导入这个文件之后,刷新数据库,发现新增了Quartz相关的数据库表。

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_开启、暂停、删除_02

具体每张表的说明:

1.qrtz_blob_triggers:Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)

2.qrtz_calendars:以 Blob 类型存储 Quartz 的 Calendar 信息 

3.qrtz_cron_triggers:存储 Cron Trigger,包括 Cron表达式和时区信息 

4.qrtz_fired_triggers:存储与已触发的 Trigger 相关的状态信息,以及相联 Job的执行信息

5.qrtz_job_details:存储每一个已配置的Job的详细信息

6.qrtz_locks:存储程序的悲观锁的信息(假如使用了悲观锁)

7,qrtz_paused_trigger_grps:存储已暂停的 Trigger 组的信息

8.qrtz_scheduler_state:存储少量的有关 Scheduler 的状态信息,和别的 Scheduler实例(假如是用于一个集群中)

9.qrtz_simple_triggers:存储简单的Trigger,包括重复次数,间隔,以及已触的次数

10.qrtz_simprop_triggers:存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器。

11.qrtz_triggers:存储已配置的 Trigger 的信息

4.创建相关实体类

package com.example.hellodemo.bean;

import lombok.Data;

import java.io.Serializable;

/**
 * @author qx
 * @date 2023/11/27
 * @des 定时内容实体
 */
@Data
public class JobDetailModel implements Serializable {

    private String content;

    private Integer type;

}
package com.example.hellodemo.bean;

import lombok.Data;

import java.io.Serializable;

/**
 * @author qx
 * @date 2023/11/27
 * @des 操作类型实体
 */
@Data
public class OperationModel implements Serializable {

    private String jobName;

    private String jobGroup;

}
package com.example.hellodemo.bean;

import lombok.Data;

import java.io.Serializable;

/**
 * @author qx
 * @date 2023/11/27
 * @des 定时任务实体类
 */
@Data
public class QuartzModel implements Serializable {

    private String cron;

    private String jobGroup;

    private String jobName;

    private String triggerGroup;

    private String triggerName;

    private JobDetailModel jobData;

}

5.实现定时任务执行器

package com.example.hellodemo.task;

import com.example.hellodemo.bean.JobDetailModel;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.util.Date;

/**
 * @author qx
 * @date 2023/11/24
 * @des 定时任务执行器
 */
@Slf4j
public class SimpleTask extends QuartzJobBean {

    /**
     * 根据不同的jobDetail携带的type参数区分不同的业务
     */
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        synchronized (this) {
            log.info("开始执行定时任务...........");
            JobDetailModel jobDetailModel = (JobDetailModel) context.getJobDetail().getJobDataMap().get("jobDetailModel");
            Integer type = jobDetailModel.getType();
            String content = jobDetailModel.getContent();
            try {
                switch (type) {
                    case 1:
                        log.info("task1被执行,content:{}", content);
                        Thread.sleep(5000);
                        log.info("-------task1定时任务执行结束------");
                        break;
                    case 2:
                        log.info("task2被执行,content:{}", content);
                        Thread.sleep(5000);
                        log.info("-------task2定时任务执行结束------");
                        break;
                    default:
                        log.info("-------定时任务执行结束------");
                        log.info("-------定时任务执行结束------");
                }
            } catch (Throwable t) {
                log.error(t.getMessage(), t);
            }
            log.info("定时任务执行结束..............");
        }
    }
}

5.创建服务层及其实现类

服务层QuartzService

package com.example.hellodemo.service;

import com.example.hellodemo.bean.OperationModel;
import com.example.hellodemo.bean.QuartzModel;
import org.quartz.SchedulerException;

import java.util.List;
import java.util.Map;

/**
 * @author qx
 * @date 2023/11/27
 * @des Quartz服务层
 */
public interface QuartzService {

    /**
     * 新增定时任务
     */
    Boolean addJob(QuartzModel quartzModel) throws SchedulerException;

    /**
     * 暂停定时任务
     */
    Boolean pauseJob(OperationModel operationModel) throws SchedulerException;

    /**
     * 继续定时任务
     */
    Boolean resumeJob(OperationModel operationModel) throws SchedulerException;

    /**
     * 删除定时任务
     */
    Boolean deleteJob(OperationModel operationModel) throws SchedulerException;

    /**
     * 查询所有计划中的任务列表
     */
    List<Map<String, Object>> queryAllJob() throws SchedulerException;

    /**
     * 查询正在运行的任务
     */
    List<Map<String, Object>> queryAllRunningJob() throws SchedulerException;
}

服务层实现类QuartzServiceImpl

package com.example.hellodemo.service.impl;

import com.example.hellodemo.bean.JobDetailModel;
import com.example.hellodemo.bean.OperationModel;
import com.example.hellodemo.bean.QuartzModel;
import com.example.hellodemo.service.QuartzService;
import com.example.hellodemo.task.SimpleTask;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author qx
 * @date 2023/11/27
 * @des Quartz服务层实现类
 */
@Slf4j
@Service
public class QuartzServiceImpl implements QuartzService {

    @Autowired
    private Scheduler scheduler;

    @Override
    public Boolean addJob(QuartzModel quartzModel) throws SchedulerException {
        log.info("quartzModel:{}", quartzModel);
        String cron = quartzModel.getCron();
        JobDetail jobDetail = JobBuilder.newJob(SimpleTask.class).withIdentity(quartzModel.getJobName(), quartzModel.getJobGroup()).build();
        JobDetailModel jobDetailModel = quartzModel.getJobData();
        if (!Objects.isNull(jobDetailModel)) {
            jobDetail.getJobDataMap().put("jobDetailModel", jobDetailModel);
        }
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzModel.getTriggerName(), quartzModel.getTriggerGroup()).startNow()
                .withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.standby();
        log.info("----定时任务成功添加进quartz队列中----");
        return true;
    }

    @Override
    public Boolean pauseJob(OperationModel operationModel) throws SchedulerException {
        scheduler.pauseJob(JobKey.jobKey(operationModel.getJobName(), operationModel.getJobGroup()));
        log.info("暂停定时任务成功");
        return true;
    }

    @Override
    public Boolean resumeJob(OperationModel operationModel) throws SchedulerException {
        scheduler.resumeJob(JobKey.jobKey(operationModel.getJobName(), operationModel.getJobGroup()));
        log.info("恢复定时任务成功");
        return true;
    }

    @Override
    public Boolean deleteJob(OperationModel operationModel) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(operationModel.getJobName(), operationModel.getJobGroup());
        // 停止触发器
        scheduler.resumeTrigger(triggerKey);
        // 移除触发器
        scheduler.unscheduleJob(triggerKey);
        scheduler.deleteJob(JobKey.jobKey(operationModel.getJobName(), operationModel.getJobGroup()));
        log.info("删除定时任务成功");
        return true;
    }

    @Override
    public List<Map<String, Object>> queryAllJob() throws SchedulerException {
        List<Map<String, Object>> jobList = new ArrayList<>();
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                jobList.add(this.buildMap(jobKey, trigger));
            }
        }
        return jobList;
    }

    @Override
    public List<Map<String, Object>> queryAllRunningJob() throws SchedulerException {
        List<Map<String, Object>> jobList = new ArrayList<>();
        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
        for (JobExecutionContext executingJob : executingJobs) {
            JobDetail jobDetail = executingJob.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            Trigger trigger = executingJob.getTrigger();
            jobList.add(this.buildMap(jobKey, trigger));
        }
        return jobList;
    }

    /**
     * 返回指定的map集合
     */
    private Map<String, Object> buildMap(JobKey jobKey, Trigger trigger) throws SchedulerException {
        Map<String, Object> map = new HashMap<>();
        map.put("jobName", jobKey.getName());
        map.put("jobGroupName", jobKey.getGroup());
        map.put("description", "触发器:" + trigger.getKey());
        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
        map.put("jobStatus", triggerState.name());
        if (trigger instanceof CronTrigger) {
            CronTrigger cronTrigger = (CronTrigger) trigger;
            String cronExpression = cronTrigger.getCronExpression();
            map.put("jobTime", cronExpression);
        }
        return map;
    }
}

6.创建控制层

package com.example.hellodemo.controller;

import com.example.hellodemo.bean.OperationModel;
import com.example.hellodemo.bean.QuartzModel;
import com.example.hellodemo.service.QuartzService;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

/**
 * @author qx
 * @date 2023/11/27
 * @des Quartz控制层
 */
@RestController
@RequestMapping("/quartz")
public class QuartzController {

    @Autowired
    private QuartzService quartzService;

    /**
     * 新增定时任务
     */
    @PostMapping("/add")
    public Boolean addTask(@RequestBody QuartzModel quartzModel) throws SchedulerException {
        return quartzService.addJob(quartzModel);
    }

    /**
     * 暂停定时任务
     */
    @PostMapping("/pause")
    public Boolean pauseTask(@RequestBody OperationModel operationModel) throws SchedulerException {
        return quartzService.pauseJob(operationModel);
    }

    /**
     * 恢复定时任务
     */
    @PostMapping("/resume")
    public Boolean resumeTask(@RequestBody OperationModel operationModel) throws SchedulerException {
        return quartzService.resumeJob(operationModel);
    }

    /**
     * 删除定时任务
     */
    @PostMapping("/delete")
    public Boolean deleteTask(@RequestBody OperationModel operationModel) throws SchedulerException {
        return quartzService.deleteJob(operationModel);
    }

    /**
     * 查看所有定时任务
     */
    @GetMapping("/queryAllJob")
    public List<Map<String, Object>> queryAllJob() throws SchedulerException {
        return quartzService.queryAllJob();
    }

    /**
     * 查看所有正在运行的定时任务
     */
    @GetMapping("/queryAllRunningJob")
    public List<Map<String, Object>> queryAllRunningJob() throws SchedulerException {
        return quartzService.queryAllRunningJob();
    }
}

三、测试

1.添加定时任务1

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_开启、暂停、删除_03

2023-11-27 10:12:08.885  INFO 10392 --- [nio-8080-exec-1] c.e.h.service.impl.QuartzServiceImpl     : quartzModel:QuartzModel(cron=*/5 * * * * ?, jobGroup=job_group_task1, jobName=job_name_task1, triggerGroup=trigger_group_task1, triggerName=trigger_task1, jobData=JobDetailModel(content=定时任务自定义内容, type=1))
2023-11-27 10:12:08.928  INFO 10392 --- [nio-8080-exec-1] org.quartz.core.QuartzScheduler          : Scheduler clusteredScheduler_$_NON_CLUSTERED paused.
2023-11-27 10:12:08.928  INFO 10392 --- [nio-8080-exec-1] c.e.h.service.impl.QuartzServiceImpl     : ----定时任务成功添加进quartz队列中----
2023-11-27 10:12:10.044  INFO 10392 --- [eduler_Worker-1] com.example.hellodemo.task.SimpleTask    : 开始执行定时任务...........
2023-11-27 10:12:10.044  INFO 10392 --- [eduler_Worker-1] com.example.hellodemo.task.SimpleTask    : task1被执行,content:定时任务自定义内容
2023-11-27 10:12:15.046  INFO 10392 --- [eduler_Worker-1] com.example.hellodemo.task.SimpleTask    : -------task1定时任务执行结束------
2023-11-27 10:12:15.046  INFO 10392 --- [eduler_Worker-1] com.example.hellodemo.task.SimpleTask    : 定时任务执行结束..............

2.添加定时任务2

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_开启、暂停、删除_04

我们查询数据库,发现添加的定时任务添加到了数据库对应的表之中。

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_开启、暂停、删除_05

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_定时任务_06

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_Quartz_07

3.获取所有定时任务

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_开启、暂停、删除_08

4.获取所有正在运行的定时任务

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_Quartz_09

5.暂停定时任务

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_Quartz_10

我们再次查询正在运行的定时任务,发现只有一个正在运行的定时任务了。task2被我们暂停了。

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_Quartz_11

6.恢复定时任务

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_定时任务_12

继续查询正在运行的定时任务,发现又有两个正在运行的定时任务了。我们查看日志也可以看到两个定时任务在同时运行。

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_定时任务_13

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_Quartz_14

7.删除定时任务

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_Quartz_15

获取所有定时任务,发现task2的定时任务已经被删除了。

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_开启、暂停、删除_16

我们在控制台上发现只有task1定时任务相关的日志了。

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_开启、暂停、删除_17

对应的数据库表中的数据也已经被删除掉了。

SpringBoot集成Quartz实现定时任务启动、暂停(恢复)、删除等操作_定时任务_18


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月05日 0

暂无评论

推荐阅读
19qMgiCiiRfc