【微服务】springboot整合quartz使用详解

目录

一、前言

二、quartz介绍

2.1 quartz概述

2.2 quartz优缺点

2.3 quartz核心概念

2.3.1 Scheduler

2.3.2 Trigger

2.3.3 Job

2.3.4 JobDetail

2.4 Quartz作业存储类型

2.5 适用场景

三、Cron表达式

3.1 Cron表达式语法

3.2 Cron表达式各元素说明

3.3 Cron表达式字符说明

四、环境准备

4.1 搭建步骤

4.1.1 拉取镜像

4.1.2 创建相关的数据目录

4.1.3 启动容器

五、springboot整合quartz

5.1 导入maven依赖

5.2 初始化数据表

5.3 增加配置文件

5.4 核心业务类

5.4.1 前端控制器类

5.4.2 业务实现类

5.4.3 mybatis-plus配置类

5.4.4 job执行任务类

5.5 效果测试

5.5.1 添加任务

5.5.2 暂停任务

5.6 补充说明

六、写在结尾


一、前言

在项目开发中,经常需要定时任务来处理一些业务,可以说定时任务的场景无处不在,比如定时同步数据,定时清理数据等,在使用SpringBoot框架中,简单的场景,可以考虑使用内置的注解就可以使用,但是如果需要调度的场景比较复杂,或者说需要更灵活的配置调度,就需要考虑采用其他的方案了,比如Quartz , xxl-job,elastic job等。

二、quartz介绍

2.1 quartz概述

Quartz 是 OpenSymphony 开源组织在 Job Scheduling 领域又一个开源项目,是完全由 Java 开发的一个开源任务日程管理系统,“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。Quartz 是一个开源的作业调度框架,它完全由 Java 写成,并设计用于 J2SE 和 J2EE 应用中,它提供了巨大的灵活性而不牺牲简单性。

官网地址:Quartz Enterprise Job Scheduler

2.2 quartz优缺点

quartz具备如下优点:

  • 丰富的 Job 操作 API;
  • 支持多种配置;
  • SpringBoot 无缝集成;
  • 支持数据持久化;
  • 支持集群部署;

Quartz 还支持开源,是一个功能丰富的开源作业调度库,可以集成到几乎任何 Java 应用程序中;

缺点:

  • 学习成本:由于Quartz是一个相对复杂的框架,使用它需要一定的学习成本。开发人员需要熟悉其概念、配置和API,以正确地使用和管理任务调度;
  • 配置复杂性:Quartz的配置文件较为复杂,特别是在涉及到分布式环境或复杂任务依赖关系时。正确配置和管理Quartz调度器可能需要一定的技术知识和经验‘

 

2.3 quartz核心概念

在真正开始学习quartz之前,有必要对quartz中的几个核心业务概念做全面的了解。下面几个核心组件的关系如下:

2.3.1 Scheduler

Quartz 中的任务调度器,通过 Trigger 和 JobDetail 可以用来调度、暂停和删除任务,提供调度任务的主要API;

调度器就相当于一个容器,装载着任务和触发器,该类是一个接口,代表一个 Quartz 的独立运行容器,Trigger 和 JobDetail 可以注册到 Scheduler 中,两者在 Scheduler 中拥有各自的组及名称,组及名称是 Scheduler 查找定位容器中某一对象的依据,Trigger 的组及名称必须唯一,JobDetail 的组和名称也必须唯一(但可以和 Trigger 的组和名称相同,因为它们是不同类型的);

2.3.2 Trigger

定义调度执行计划的组件,即什么时候触发执行,Trigger是Quartz 中的触发器,是一个类,描述触发 Job 执行的时间触发规则,主要有 SimpleTrigger 和 CronTrigger 这两个子类。

1)当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger 是最适合的选择;

2)CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度方案:如工作日周一到周五的 16:00 ~16:10 执行调度等;

2.3.3 Job

Quartz 中具体的任务,包含了执行任务的具体方法,是一个接口,只定义一个方法 execute() 方法,在实现接口的 execute() 方法中编写所需要定时执行的 Job。

2.3.4 JobDetail

Quartz 中需要执行的任务详情,包括了任务的唯一标识和具体要执行的任务,可以通过 JobDataMap 往任务中传递数据。

2.4 Quartz作业存储类型

RAMJobStore

RAM 也就是内存,默认情况下 Quartz 会将任务调度存储在内存中,这种方式性能是最好的,因为内存的速度是最快的。不好的地方就是数据缺乏持久性,但程序崩溃或者重新发布的时候,所有运行信息都会丢失

JDBC 作业存储

存到数据库之后,可以做单点也可以做集群,当任务多了之后,可以统一进行管理,随时停止、暂停、修改任务。关闭或者重启服务器,运行的信息都不会丢失。缺点就是运行速度快慢取决于连接数据库的快慢

2.5 适用场景

在下面的场景中你可以考虑适用quartz

定时任务

Quartz最常见的应用场景是执行定时任务,比如每天凌晨生成报表、每小时执行数据备份等。它可以根据配置的时间表触发任务,并在预定的时间间隔内重复执行。

计划任务

除了定时任务,Quartz还支持基于日历的计划任务。例如,在特定的日期或周几执行某个任务,或者排除特定的日期和时间段。

分布式任务调度

Quartz可以与分布式系统集成,实现分布式任务调度。它提供了可靠的任务调度机制,能够确保在分布式环境中准确地调度和执行任务。

监控和管理

Quartz提供了监控和管理任务的功能。它可以获取任务的执行状态、日志和性能指标,并提供了对任务的管理接口,如启动、停止、暂停和恢复任务等。

三、Cron表达式

Cron 表达式是任务调度的关键要素,简单来说,Cron 表达式是一个字符串,包括6~7个时间元素,每个元素都有特定的含义,在 Quartz中可以用于指定任务的执行时间。比如:0/10 * * * * ?

3.1 Cron表达式语法

cron表达式中各个位置的元素代表的含义如下

SecondsMinutesHoursDayofMonthMonthDayofWeek
分钟小时日期天/日日期月份星期

3.2 Cron表达式各元素说明

cron表达式中各个位置的元素的用法参考如下

时间元素可出现的字符有效数值范围
Seconds, - * /0-59
Minutes, - * /0-59
Hours, - * /0-23
DayofMonth, - * / ? L W0-31
Month, - * /1-12
DayofWeek, - * / ? L #1-7或SUN-SAT

3.3 Cron表达式字符说明

字符作用举例
,列出枚举值在Minutes域使用5,10,表示在5分和10分各触发一次
-表示触发范围在Minutes域使用5-10,表示从5分到10分钟每分钟触发一次
*匹配任意值在Minutes域使用*, 表示每分钟都会触发一次
/

起始时间开始触发,每隔固定时间触发

一次

在Minutes域使用5/10,表示5分时触发一次,每10分钟再触发一次
?

在DayofMonth和DayofWeek中,用于匹

配任意值

在DayofMonth域使用?,表示每天都触发一次
#在DayofMonth中,确定第几个星期几1#3表示第三个星期日
L表示最后在DayofWeek中使用5L,表示在最后一个星期四触发
W表示有效工作日(周一到周五)在DayofMonth使用5W,如果5日是星期六,则将在最近的工作日4日触发一次

在线 Cron 表达式生成器,其实 Cron 表达式无需多记,需要使用的时候直接使用在线生成器就可以了

地址1: 在线Cron表达式生成器

地址2: 在线Cron表达式生成器

四、环境准备

在实际使用quartz时,任务调度相关的配置数据肯定是要入库的,即Quartz作业存储类型使用jdbc作业存储,所以需要准备mysql环境,下面使用docker快速搭建mysql环境。

4.1 搭建步骤

4.1.1 拉取镜像

docker pull mysql:5.7

4.1.2 创建相关的数据目录

mkdir -p /usr/local/mysql/datamkdir -p /usr/local/mysql/logsmkdir -p /usr/local/mysql/conf

4.1.3 启动容器

docker run --name mysql -p 3306:3306 \
-v /usr/local/mysql/data:/var/lib/mysql \
-v /usr/local/mysql/logs:/logs \
-v /usr/local/mysql/conf:/etc/mysql/conf.d \-e MYSQL_ROOT_PASSWORD=密码 -d mysql:5.7

五、springboot整合quartz

网上关于quartz与springboot的整合方式有很多,但很多样例无法跑起来,请参选接下来的操作步骤,完成一个完整的整合。完整的工程目录如下:

5.1 导入maven依赖

以下为本例必须的依赖,可以根据自身的情况酌情添加

    <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.2</version><relativePath/></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.1.4</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency></dependencies>

5.2 初始化数据表

上面导入完成依赖jar包之后,在依赖的jar包中,找到与调度任务初始化的一个sql

拷贝上面的sql文件中的初始化sql,在mysql中创建一个数据库,这里命名为:quartz_db,然后执行即可,执行成功后,可以看到与任务调度相关的数据表就初始化了

在此基础上,再额外增加一张表,与我们可能有业务关联的信息整合

DROP TABLE IF EXISTS `sys_quartz_job`;CREATE TABLE `sys_quartz_job`  (`id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`create_by` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',`del_flag` int(1) NULL DEFAULT NULL COMMENT '删除状态',`update_by` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',`update_time` datetime NULL DEFAULT NULL COMMENT '修改时间',`job_class_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '任务类名',`cron_expression` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'cron表达式',`parameter` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '参数',`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',`status` int(1) NULL DEFAULT NULL COMMENT '状态 0正常 -1停止',PRIMARY KEY (`id`) USING BTREE) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;

5.3 增加配置文件

配置application.yml文件

server:port: 8088
spring:## quartz定时任务,采用数据库方式quartz:job-store-type: jdbc#json 时间戳统一转换jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8datasource:url: jdbc:mysql://IP:3306/quartz_db?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&useSSL=falseusername: rootpassword: 密码driver-class-name: com.mysql.jdbc.Driverjta:atomikos:properties:recovery:forget-orphaned-log-entries-delay:
#mybatis plus 设置
mybatis-plus:mapper-locations: classpath:resources/mapper/*global-config:# 关闭MP3.0自带的bannerbanner: falsedb-config:#主键类型  0:"数据库ID自增",1:"该类型为未设置主键类型", 2:"用户输入ID",3:"全局唯一ID (数字类型唯一ID)", 4:"全局唯一ID UUID",5:"字符串全局唯一ID (idWorker 的字符串表示)";table-underline: truelogic-delete-value: 1 # 逻辑已删除值(默认为 1)logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)configuration:# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 返回类型为Map,显示null对应的字段call-setters-on-nulls: truelog-impl:   org.apache.ibatis.logging.stdout.StdOutImpl

5.4 核心业务类

下面列举出工程中核心的类文件,编写的顺序为从上至下,即从接口开始

5.4.1 前端控制器类

该类主要提供与交互操作相关的API接口,后续可以通过界面的配置方式操作任务

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.congge.common.CommonConstant;
import com.congge.common.Result;
import com.congge.entity.QuartzJob;
import com.congge.exception.BizException;
import com.congge.service.QuartzJobService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;import java.util.Arrays;
import java.util.List;@Slf4j
@RestController
@RequestMapping("/job")
public class QuartzController {@Autowiredprivate QuartzJobService quartzJobService;@Autowiredprivate Scheduler scheduler;/*** 分页列表查询** @return*/@RequestMapping(value = "/list", method = RequestMethod.GET)public Result<?> queryPageList(QuartzJob quartzJob, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {Page<QuartzJob> page = new Page<QuartzJob>(pageNo, pageSize);IPage<QuartzJob> pageList = quartzJobService.page(page);return Result.ok(pageList);}/*** 添加定时任务** @param quartzJob* @return*/@PostMapping("/add")public Result<?> add(@RequestBody QuartzJob quartzJob) {List<QuartzJob> list = quartzJobService.list(new QueryWrapper<QuartzJob>().eq("job_class_name", quartzJob.getJobClassName()));if (list != null && list.size() > 0) {return Result.error("该定时任务类名已存在");}quartzJobService.saveAndScheduleJob(quartzJob);return Result.ok("创建定时任务成功");}/*** 更新定时任务** @param quartzJob* @return*/@PostMapping("/edit")public Result<?> eidt(@RequestBody QuartzJob quartzJob) {try {quartzJobService.editAndScheduleJob(quartzJob);} catch (SchedulerException e) {log.error(e.getMessage(), e);return Result.error("更新定时任务失败!");}return Result.ok("更新定时任务成功!");}/*** 通过id删除** @param id* @return*/@GetMapping("/delete")public Result<?> delete(@RequestParam(name = "id", required = true) String id) {QuartzJob quartzJob = quartzJobService.getById(id);if (quartzJob == null) {return Result.error("未找到对应实体");}quartzJobService.deleteAndStopJob(quartzJob);return Result.ok("删除成功!");}/*** 批量删除** @param ids* @return*/@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {if (ids == null || "".equals(ids.trim())) {return Result.error("参数不识别!");}for (String id : Arrays.asList(ids.split(","))) {QuartzJob job = quartzJobService.getById(id);quartzJobService.deleteAndStopJob(job);}return Result.ok("删除定时任务成功!");}/*** 暂停定时任务** @param jobClassName* @return*/@GetMapping(value = "/pause")public Result<Object> pauseJob(@RequestParam(name = "jobClassName", required = true) String jobClassName) {QuartzJob job = null;try {job = quartzJobService.getOne(new LambdaQueryWrapper<QuartzJob>().eq(QuartzJob::getJobClassName, jobClassName));if (job == null) {return Result.error("定时任务不存在!");}scheduler.pauseJob(JobKey.jobKey(jobClassName.trim()));} catch (SchedulerException e) {throw new BizException("暂停定时任务失败");}job.setStatus(CommonConstant.STATUS_DISABLE);quartzJobService.updateById(job);return Result.ok("暂停定时任务成功");}/*** 恢复定时任务** @param jobClassName* @return*/@GetMapping(value = "/resume")public Result<Object> resumeJob(@RequestParam(name = "jobClassName", required = true) String jobClassName) {QuartzJob job = quartzJobService.getOne(new LambdaQueryWrapper<QuartzJob>().eq(QuartzJob::getJobClassName, jobClassName));if (job == null) {return Result.error("定时任务不存在!");}quartzJobService.resumeJob(job);//scheduler.resumeJob(JobKey.jobKey(job.getJobClassName().trim()));return Result.ok("恢复定时任务成功");}/*** 通过id查询** @param id* @return*/@GetMapping("/queryById")public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {QuartzJob quartzJob = quartzJobService.getById(id);return Result.ok(quartzJob);}
}

5.4.2 业务实现类

接口控制器的业务逻辑实现

import com.congge.common.CommonConstant;
import com.congge.entity.QuartzJob;
import com.congge.exception.BizException;
import com.congge.mapper.QuartzJobMapper;
import com.congge.service.QuartzJobService;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import lombok.extern.slf4j.Slf4j;@Slf4j
@Service
public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob> implements QuartzJobService {//    @Autowired
//    private QuartzJobMapper quartzJobMapper;@Autowiredprivate Scheduler scheduler;/*** 保存&启动定时任务*/@Overridepublic boolean saveAndScheduleJob(QuartzJob quartzJob) {if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) {// 定时器添加this.schedulerAdd(quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter());}// DB设置修改return this.save(quartzJob);}/*** 恢复定时任务*/@Overridepublic boolean resumeJob(QuartzJob quartzJob) {schedulerDelete(quartzJob.getJobClassName().trim());schedulerAdd(quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter());quartzJob.setStatus(CommonConstant.STATUS_NORMAL);return this.updateById(quartzJob);}@Overridepublic void test(String param) {System.out.println("param====>"+param);}/*** 编辑&启停定时任务* @throws SchedulerException*/@Overridepublic boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException {if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) {schedulerDelete(quartzJob.getJobClassName().trim());schedulerAdd(quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter());}else{scheduler.pauseJob(JobKey.jobKey(quartzJob.getJobClassName().trim()));}return this.updateById(quartzJob);}/*** 删除&停止删除定时任务*/@Overridepublic boolean deleteAndStopJob(QuartzJob job) {schedulerDelete(job.getJobClassName().trim());return this.removeById(job.getId());}/*** 添加定时任务** @param jobClassName* @param cronExpression* @param parameter*/private void schedulerAdd(String jobClassName, String cronExpression, String parameter) {try {// 启动调度器scheduler.start();// 构建job信息JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobClassName).usingJobData("parameter", parameter).build();// 表达式调度构建器(即任务执行的时间)CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);// 按新的cronExpression表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName).withSchedule(scheduleBuilder).build();scheduler.scheduleJob(jobDetail, trigger);} catch (SchedulerException e) {throw new BizException("创建定时任务失败", e);} catch (RuntimeException e) {throw new BizException(e.getMessage(), e);}catch (Exception e) {throw new BizException("后台找不到该类名:" + jobClassName, e);}}/*** 删除定时任务** @param jobClassName*/private void schedulerDelete(String jobClassName) {try {/*使用给定的键暂停Trigger 。*/scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName));/*从调度程序中删除指示的Trigger */scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName));/*从 Scheduler 中删除已识别的Job - 以及任何关联的Trigger */scheduler.deleteJob(JobKey.jobKey(jobClassName));} catch (Exception e) {log.error(e.getMessage(), e);throw new BizException("删除定时任务失败");}}private static Job getClass(String classname) throws Exception {Class<?> class1 = Class.forName(classname);return (Job) class1.newInstance();}}

5.4.3 mybatis-plus配置类

MybatisPlusConfig,配置分页信息

@Configuration
public class MybatisPlusConfig {/*** 分页*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));// 注册乐观锁 插件return mybatisPlusInterceptor;}}

MyMetaObjectHandler,统一处理时间日期等字段信息

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {this.setFieldValByName("createTime",new Date(),metaObject);this.setFieldValByName("updateTime",new Date(),metaObject);}@Overridepublic void updateFill(MetaObject metaObject) {this.setFieldValByName("updateTime",new Date(),metaObject);}
}

5.4.4 job执行任务类

在实际开发中,具体执行各类业务时,需要根据需求场景编写任务执行类,下面提供两个测试使用的任务类

不带参数的任务

@Slf4j
public class SampleJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {log.info(String.format("执行普通定时任务 SampleJob !  当前时间:" + new Date()));}}

带任务参数

import com.congge.service.QuartzJobService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;@Component
@Slf4j
public class SampleParamJob implements Job {@Autowiredprivate QuartzJobService quartzJobService;/*** 若参数变量名修改 QuartzJobController中也需对应修改*/private String parameter;public void setParameter(String parameter) {this.parameter = parameter;}@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {log.info(String.format("准备执行带参数定时任务 SampleParamJob !   时间:" + LocalDateTime.now(), this.parameter));quartzJobService.test(this.parameter);}}

5.5 效果测试

5.5.1 添加任务

使用postman调用添加任务的接口

执行成功后,从控制台可以看到,任务已经在执行了

同时数据库也增加了一条数据

5.5.2 暂停任务

浏览器调用接口:localhost:8088/job/pause?jobClassName=com.congge.job.SampleJob

调用成功后,可以从控制台看到任务已经停止执行了

其他的测试用例可以参照上面的方式继续测试即可。

5.6 补充说明

基于上面的整合和效果验证,下面留待几个问题请进一步思考和探究

问题1:

如何让任务添加成功后延迟一段时间执行?

问题2:

 如何解决任务的并发执行?

问题3:

 两次执行任务的时间间隔太短怎么办?

六、写在结尾

相对其他的分布式任务调度框架,quartz整体来说学习成本不算高,而且适用的场景也比较多,在项目中合理的引用,可以灵活的解决很多问题。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/255988.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

配置BFD状态与接口状态联动示例

1、BFD检测IP链路。 在IP链路上建立BFD会话&#xff0c;利用BFD检测机制快速检测故障。BFD检测IP链路支持单跳检测和多跳检测&#xff1a; BFD单跳检测是指对两个直连系统进行IP连通性检测&#xff0c;“单跳”是IP链路的一跳。 BFD多跳检测是指BFD可以检测两个系统间的任意路…

UDP通讯

本章节主要讲解的是TCP和UDP两种通信方式它们都有着自己的优点和缺点 这两种通讯方式不通的地方就是TCP是一对一通信 UDP是一对多的通信方式 接下来会一一讲解 UDP通信 主要的方向是一对多通信方式 UDP通信就是一下子可以通信多个对象&#xff0c;这就是UDP对比TCP的优势&am…

股市复苏中的明懿金汇:抓住新机遇

2023年对于明懿金汇来说是充满挑战与机遇的一年。面对复杂多变的市场环境&#xff0c;明懿金汇展现了其对市场趋势的敏锐洞察和卓越的策略适应能力。以下是该公司在2023年的主要投资策略和市场适应方式的详细分析。 随着2023年中国股市迎来反弹&#xff0c;明懿金汇迅速调整了…

Day04 Liunx高级系统设计4-信号

进程间通讯 引入 如何将 A 进程中的数据传入 B 进程呢 ? 我们要使用进程间通讯 概述 中文名 : 进程间通讯 英文名 :IPC 英文全称 :Inter Processes Communication 作用: 数据传输&#xff1a;一个进程需要将他的数据发送给另一个进程】 资源共享&#xff1a;多个进程可以…

从文字到使用,一文读懂Kafka服务使用

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

C++入门第十一篇----多态

前言&#xff1a; 和前面的继承一样&#xff0c;多态也是对类和对象的功能进行扩展&#xff0c;以让其更加好用的一个知识点&#xff0c;接下来&#xff0c;就让我们总结一下多态&#xff0c;这个依托了继承的一个重要知识点。 对多态的理解和多态的概念&#xff1a; 何为多…

如何把数据变成资产,企业数据资产化实施路径三部曲

在数字化时代&#xff0c;数据已经成为一种重要的资产&#xff0c;企业和个人都希望能够将数据变现。但并不是所有的数据都是资产&#xff0c;如何成为资产是当下企业关心的问题。下面就让我们一起来了解一下企业数据资产化的三个关键步骤&#xff1a;数据资源化、资源产品化和…

学习SQL大概要多久?有没有好的资料或者视频推荐呢?

【关注微信公众号&#xff1a;跟强哥学SQL&#xff0c;回复“笔试”免费领取大厂SQL笔试题。】 一、SQL认知 SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和操作关系型数据库的标准化语言。通过SQL&#xff0c;使用简单的关键词和语法来表达复杂的数…

C++新经典模板与泛型编程:用成员函数重载实现std::is_class

用成员函数重载实现is_class std::is_class功能&#xff0c;是一个C11标准中用于判断某个类型是否为一个类类型&#xff08;但不是联合类型&#xff09;的类模板。当时在讲解的时候并没有涉及std::is_class的实现代码&#xff0c;在这里实现一下。简单地书写一个IsClass类模板…

1.10 C语言之外部变量与作用域

1.10 C语言之外部变量与作用域 一、外部变量概述二、练习 一、外部变量概述 我们说&#xff0c;函数&#xff08;不管是main函数还是其他函数&#xff09;内部定义的变量&#xff0c;其作用范围都只在函数内部&#xff0c;我们把这些变量叫做自动变量或者局部变量。除了局部变…

[数据集][目标检测]拉横幅识别横幅检测数据集VOC+yolo格式1962张1类别

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1962 标注数量(xml文件个数)&#xff1a;1962 标注数量(txt文件个数)&#xff1a;1962 标注类别数&a…

网络机房的功能有哪些?

网络机房的功能主要包括&#xff1a; 信息存储和管理&#xff1a;机房作为信息系统的核心&#xff0c;需要提供可靠的存储和管理能力&#xff0c;包括服务器、存储设备、备份系统等硬件设备&#xff0c;以及数据备份、数据迁移、容灾等管理方法和技术。网络连接和通信&#xf…