XXJ-JOB任务调度
官方文档:https://www.xuxueli.com/xxl-job/
概述
XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
文档地址
一、快速入门
依赖
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${最新稳定版本}</version>
</dependency>
1 导入项目到idea
![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=assets%5C1690169616781.png&pos_id=img-s6gh5jCO-1728796431068
项目结构说明:
xxl-job-master:
xxl-job-admin:调度中心
xxl-job-core:公共依赖
xxl-job-executor-samples:执行器Sample示例(选择合适的版本执行器,可直接使用,也可以参考其并将现有项目改造成执行器)
xxl-job-executor-sample-springboot:Springboot版本,通过Springboot管理执行器,推荐这种方式;
xxl-job-executor-sample-frameless:无框架版本;
2 初始化数据库
获取 “调度数据库初始化SQL脚本” 并执行即可。
调度数据库初始化SQL脚本” 位置为:/xxl-job-master/doc/db/tables_xxl_job.sql
3 部署调度中心:xxl-job-admin
3.1 修改数据库连接
打开xxl-job-admin的application.propertiest。路径:xxl-job-admin\src\main\resources\application.properties
修改数据库连接信息:
spring.datasource.url=jdbc:mysql://localhost:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
### 记得改数据库ip地址
spring.datasource.username=root
### 数据库密码改成你自己的
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
完整的application.properties配置信息:
### web
# 指定服务运行的端口号,默认为8080
server.port=8080
# 设置web应用的访问路径前缀
server.servlet.context-path=/xxl-job-admin
### actuator
# 设置actuator端点的基础路径
management.server.base-path=/actuator
# 禁用邮件健康检查功能,因为可能需要额外的配置才能使用
management.health.mail.enabled=false
### resources
# 设置Spring MVC Servlet的启动加载顺序,值为0表示随容器启动而加载
spring.mvc.servlet.load-on-startup=0
# 配置静态资源的访问路径,例如图片、CSS等
spring.mvc.static-path-pattern=/static/**
# 静态资源的位置,这里指定了在类路径下的/static目录中查找
spring.web.resources.static-locations=classpath:/static/
### freemarker
# Freemarker模板文件的加载路径,这里设置为类路径下的/templates目录
spring.freemarker.templateLoaderPath=classpath:/templates/
# 设置模板文件的后缀名
spring.freemarker.suffix=.ftl
# 设置模板文件的字符集
spring.freemarker.charset=UTF-8
# 将请求对象作为属性传递给模板
spring.freemarker.request-context-attribute=request
# 设置数字格式化方式
spring.freemarker.settings.number_format=0.##########
### mybatis
# MyBatis映射文件的位置,这里指定了类路径下的/mybatis-mapper目录中的所有Mapper.xml文件
mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml
# # 如果需要指定实体类的位置,可以取消注释并设置相应的包名
# mybatis.type-aliases-package=com.xxl.job.admin.core.model
### xxl-job, datasource
# 数据库连接的URL,这里配置了MySQL数据库,指定了数据库名为xxl_job,并设置了相关参数以支持中文及自动重连
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
# 数据库用户名
spring.datasource.username=root
# 数据库密码
spring.datasource.password=1234
# 指定数据库驱动类名
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
### datasource-pool
# 指定数据源类型为HikariCP,这是一个高性能的数据库连接池
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
# 设置HikariCP最小空闲连接数
spring.datasource.hikari.minimum-idle=10
# 设置HikariCP最大连接池大小
spring.datasource.hikari.maximum-pool-size=30
# 设置是否自动提交SQL语句
spring.datasource.hikari.auto-commit=true
# 设置连接空闲超时时间(毫秒)
spring.datasource.hikari.idle-timeout=30000
# 设置连接池名称
spring.datasource.hikari.pool-name=HikariCP
# 设置连接的最大生命周期(毫秒)
spring.datasource.hikari.max-lifetime=900000
# 设置获取连接的超时时间(毫秒)
spring.datasource.hikari.connection-timeout=10000
# 设置连接测试查询语句
spring.datasource.hikari.connection-test-query=SELECT 1
# 设置验证超时时间(毫秒)
spring.datasource.hikari.validation-timeout=1000
### xxl-job, email
# 邮件服务器地址,这里配置的是QQ邮箱的SMTP服务器
spring.mail.host=smtp.qq.com
# SMTP服务器端口
spring.mail.port=25
# 发送邮件的用户名
[email protected]
# 发送邮件的默认发件人地址
[email protected]
# 发送邮件的密码或授权码
spring.mail.password=xxx
# 设置是否需要认证
spring.mail.properties.mail.smtp.auth=true
# 启用STARTTLS安全连接
spring.mail.properties.mail.smtp.starttls.enable=true
# 强制要求使用STARTTLS
spring.mail.properties.mail.smtp.starttls.required=true
# 设置用于创建安全套接字工厂的类
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
### xxl-job, access token
# 设置XXL-JOB的访问令牌,用于保护API接口
xxl.job.accessToken=default_token
### xxl-job, i18n (国际化)
# 设置XXL-JOB的界面语言,默认为简体中文,可选值还有"zh_TC"(繁体中文)和"en"(英文)
xxl.job.i18n=zh_CN
## xxl-job, triggerpool max size
# 设置快速任务触发池的最大线程数
xxl.job.triggerpool.fast.max=200
# 设置慢速任务触发池的最大线程数
xxl.job.triggerpool.slow.max=100
### xxl-job, log retention days
# 设置日志保留天数,超过该天数的日志将被自动清理
xxl.job.logretentiondays=30
3.2 启动项目
调度中心访问地址:http://localhost:8080/xxl-job-admin
默认登录账号 “admin/123456”, 登录后运行界面如下图所示:
3.3 调度中心集群部署(可选)
调度中心支持集群部署,提升调度系统容灾和可用性。
调度中心集群部署时,几点要求和建议:
- DB配置保持一致;
- 集群机器时钟保持一致(单机集群忽视);
- 建议:推荐通过nginx为调度中心集群做负载均衡,分配域名。调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。
4 配置执行器
“执行器”项目:xxl-job-executor-sample-springboot (提供多种版本执行器供选择,现以 springboot 版本为例,可直接使用,也可以参考其并将现有项目改造成执行器)
作用:负责接收“调度中心”的调度并执行;可直接部署执行器,也可以将执行器集成到现有业务项目中。
4.1 maven依赖
确认pom文件中引入了 “xxl-job-core” 的maven依赖;
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.4.1-SNAPSHOT</version>
</dependency>
4.2 执行器配置
执行器配置,配置内容说明:
### 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### 执行器通讯TOKEN [选填]:非空时启用;
xxl.job.accessToken=
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
xxl.job.executor.appname=xxl-job-executor-sample
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
xxl.job.executor.address=
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
xxl.job.executor.ip=
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
xxl.job.executor.port=9999
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
xxl.job.executor.logretentiondays=30
4.3 执行器组件配置
执行器组件,配置内容说明:
package com.xxl.job.executor.core.config;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* XXL-JOB配置类,用于初始化XXL-JOB执行器的相关配置。
*
* @author xuxueli 2017-04-28
*/
@Configuration
public class XxlJobConfig {
// 日志记录器,用于记录配置初始化过程中的日志信息
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
// 从application.properties中读取XXL-JOB管理端的地址
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
// 从application.properties中读取XXL-JOB的访问令牌,用于保护API接口
@Value("${xxl.job.accessToken}")
private String accessToken;
// 从application.properties中读取执行器的应用名称
@Value("${xxl.job.executor.appname}")
private String appname;
// 从application.properties中读取执行器的地址
@Value("${xxl.job.executor.address}")
private String address;
// 从application.properties中读取执行器的IP地址
@Value("${xxl.job.executor.ip}")
private String ip;
// 从application.properties中读取执行器的端口号
@Value("${xxl.job.executor.port}")
private int port;
// 从application.properties中读取执行器日志的存储路径
@Value("${xxl.job.executor.logpath}")
private String logPath;
// 从application.properties中读取执行器日志的保留天数
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
/**
* 创建并初始化XXL-JOB执行器的Bean。
*
* @return 初始化后的XXL-JOB执行器实例
*/
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
// 创建XXL-JOB执行器实例
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
// 设置管理端地址
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
// 设置应用名称
xxlJobSpringExecutor.setAppname(appname);
// 设置执行器地址
xxlJobSpringExecutor.setAddress(address);
// 设置执行器IP地址
xxlJobSpringExecutor.setIp(ip);
// 设置执行器端口号
xxlJobSpringExecutor.setPort(port);
// 设置访问令牌
xxlJobSpringExecutor.setAccessToken(accessToken);
// 设置日志存储路径
xxlJobSpringExecutor.setLogPath(logPath);
// 设置日志保留天数
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
/**
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP。
*
* 1. 引入依赖:
* <dependency>
* <groupId>org.springframework.cloud</groupId>
* <artifactId>spring-cloud-commons</artifactId>
* <version>${version}</version>
* </dependency>
*
* 2. 配置文件,或者容器启动变量:
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
*
* 3. 获取IP地址:
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
*/
}
详细说明
- 日志记录器:
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
- 用于记录配置初始化过程中的日志信息,方便调试和问题排查。
- 配置项注入:
- 使用
@Value
注解从application.properties
文件中读取配置项。 - 例如:
@Value("${xxl.job.admin.addresses}")
会从配置文件中读取xxl.job.admin.addresses
的值,并赋值给adminAddresses
变量。
- 使用
- Bean 创建方法:
@Bean
注解的方法用于创建并初始化一个XxlJobSpringExecutor
实例。- 在方法中,通过调用
XxlJobSpringExecutor
的各个set
方法,设置其属性值。 - 最后返回初始化好的
XxlJobSpringExecutor
实例。
- 多网卡和容器内部署:
- 对于多网卡或容器内部署的情况,可以通过
spring-cloud-commons
提供的InetUtils
组件来灵活获取注册IP。 - 需要引入
spring-cloud-commons
依赖,并在配置文件中指定优先网络段。 - 最后通过
InetUtils
获取实际的IP地址。
- 对于多网卡或容器内部署的情况,可以通过
4.4 启动xxl-job-executor-sample-springboot
5 开始第一个任务调度
5.1 配置执行器
上面我们启动了xxl-job-executor-sample-springboot 执行器项目,当前已注册上来,我们执行使用改执行器。
如果没有注册可以自己手动注册
AppName填的是执行的的application.properties里面的xxl.job.executor.appname
执行器属性说明:
AppName: 是每个执行器集群的唯一标示AppName, 执行器会周期性以AppName为对象进行自动注册。可通过该配置自动发现注册成功的执行器, 供任务调度时使用;
名称: 执行器的名称, 因为AppName限制字母数字等组成,可读性不强, 名称为了提高执行器的可读性;排序: 执行器的排序, 系统中需要执行器的地方,如任务新增, 将会按照该排序读取可用的执行器列表;
注册方式:调度中心获取执行器地址的方式;
自动注册:执行器自动进行执行器注册,调度中心通过底层注册表可以动态发现执行器机器地址;
手动录入:人工手动录入执行器的地址信息,多地址逗号分隔,供调度中心使用;
机器地址:"注册方式"为"手动录入"时有效,支持人工维护执行器的地址信息;
5.2 第一个调度任务
登录调度中心:http://localhost:8080/xxl-job-admin
默认登录账号 “admin/123456”
在xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/SampleXxlJob.java
有该方法
@Component
public class SampleXxlJob {
private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);
/**
* 1、简单任务示例(Bean模式)
*/
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println("Hello XXL-JOB");
}
}
}
任务管理 --> 新增
然后点击执行一次
回到idea控制台
成功打印十次Hello XXL-JOB。
二、集成XXL-JOB
我们使用单独的一个微服务模块service-dispatch集成XXL-JOB执行器
1 引入maven依赖
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.4.1-SNAPSHOT</version>
</dependency>
2 执行器配置
在项目的配置文件application加入下面配置
xxl:
job:
admin:
# 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册
addresses: http://localhost:8080/xxl-job-admin
# 执行器通讯TOKEN [选填]:非空时启用
accessToken:
executor:
# 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
appname: xxl-job-executor-sample
# 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
address:
# 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
ip:
# 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
port: 9999
# 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
logpath: /data/applogs/xxl-job/jobhandler
# 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
logretentiondays: 30
3 执行器组件配置
将xxl-job-executor-sample-springboot 执行器项目的XxlJobConfig类复制过来
package com.atguigu.daijia.dispatch.xxl.config;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class XxlJobConfig {
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.address}")
private String address;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
/**
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
*
* 1、引入依赖:
* <dependency>
* <groupId>org.springframework.cloud</groupId>
* <artifactId>spring-cloud-commons</artifactId>
* <version>${version}</version>
* </dependency>
*
* 2、配置文件,或者容器启动变量
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
*
* 3、获取IP
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
*/
}
我们已经将XXL-JOB集成到项目中了
4 测试任务
编写测试任务job方法
@Component
public class DispatchJobHandler {
@XxlJob("firstJobHandler")
public void firstJobHandler() {
log.info("xxl-job项目集成测试");
}
}
在调度中心配置任务
记得启动 xxl-job-admin 哦!
启动任务就可以了
三 动态创建XXL-JOB任务
有些业务需要开启任务调度,指定只能动态创建XXL-JOB任务,因此我们要封装XXL-JOB客户端,通过接口的形式添加并启动任务。
1 改造XXL-JOB服务器端接口
在xxl-job-admin模块,添加改造后的api接口
在JobInfoController类末尾添加方法,如下:
// 定义一个用于添加新任务的方法
@RequestMapping("/addJob")
@ResponseBody
@PermissionLimit(limit = false) // 表示此方法不需要权限限制
public ReturnT<String> addJobInfo(@RequestBody XxlJobInfo jobInfo) {
// 调用服务层的方法来添加新的任务信息,并返回操作结果
return xxlJobService.add(jobInfo);
}
// 定义一个用于更新现有任务的方法
@RequestMapping("/updateJob")
@ResponseBody
@PermissionLimit(limit = false) // 表示此方法不需要权限限制
public ReturnT<String> updateJob(@RequestBody XxlJobInfo jobInfo) {
// 调用服务层的方法来更新任务信息,并返回操作结果
return xxlJobService.update(jobInfo);
}
// 定义一个用于删除任务的方法
@RequestMapping("/removeJob")
@ResponseBody
@PermissionLimit(limit = false) // 表示此方法不需要权限限制
public ReturnT<String> removeJob(@RequestBody XxlJobInfo jobInfo) {
// 调用服务层的方法来移除指定ID的任务,并返回操作结果
return xxlJobService.remove(jobInfo.getId());
}
// 定义一个用于暂停任务的方法
@RequestMapping("/stopJob")
@ResponseBody
@PermissionLimit(limit = false) // 表示此方法不需要权限限制
public ReturnT<String> pauseJob(@RequestBody XxlJobInfo jobInfo) {
// 调用服务层的方法来停止指定ID的任务,并返回操作结果
return xxlJobService.stop(jobInfo.getId());
}
// 定义一个用于启动任务的方法
@RequestMapping("/startJob")
@ResponseBody
@PermissionLimit(limit = false) // 表示此方法不需要权限限制
public ReturnT<String> startJob(@RequestBody XxlJobInfo jobInfo) {
// 调用服务层的方法来启动指定ID的任务,并返回操作结果
return xxlJobService.start(jobInfo.getId());
}
// 定义一个用于添加并立即启动任务的方法
@RequestMapping("/addAndStartJob")
@ResponseBody
@PermissionLimit(limit = false) // 表示此方法不需要权限限制
public ReturnT<String> addAndStartJob(@RequestBody XxlJobInfo jobInfo) {
// 先调用服务层的方法来添加新的任务
ReturnT<String> result = xxlJobService.add(jobInfo);
// 获取新增任务的ID(从返回的结果中解析)
int id = Integer.valueOf(result.getContent());
// 启动刚刚添加的任务
xxlJobService.start(id);
// 立即执行一次该任务
JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, jobInfo.getExecutorParam(), "");
// 返回添加任务的操作结果
return result;
}
说明:排除登录校验(@PermissionLimit(limit = false))
2 配置接口地址
在自己的项目的配置文件中添加
xxl:
job:
admin:
# 调度中心部署地址 [选填]:如果调度中心是集群部署,则使用逗号分隔多个地址。执行器将使用这些地址进行“执行器心跳注册”和“任务结果回调”。如果留空,则关闭自动注册。
addresses: http://139.198.30.131:8080/xxl-job-admin
# addresses: http://localhost:8080/xxl-job-admin
# 执行器与调度中心通信的TOKEN [选填]:如果设置,将启用安全验证。
accessToken:
executor:
# 执行器的应用名称 [选填]:执行器心跳注册时使用的分组标识。如果留空,则关闭自动注册。
appname: xxl-job-executor-sample
# 执行器注册地址 [选填]:优先级高于自动获取的“IP:PORT”,适合于容器化环境中执行器的动态IP和端口映射场景。
address:
# 执行器IP [选填]:默认为空,表示自动获取IP。在多网卡环境下,可以手动指定IP。该IP仅用于执行器之间的通信。
ip:
# 执行器端口号 [选填]:小于等于0则自动获取,默认为9999。如果在同一台机器上部署了多个执行器,确保每个执行器的端口不同。
port: 9999
# 执行器运行日志的文件存储路径 [选填]:需要对这个路径有读写权限。留空则使用默认路径。
logpath: /data/applogs/xxl-job/jobhandler
# 执行器日志文件保留天数 [选填]:当值大于等于3时,过期的日志文件会被自动清理;否则,如-1,关闭自动清理功能。
logretentiondays: 30
client:
# 任务组ID [选填]:通常情况下不需要更改。
jobGroupId: 1
#下面的路径要对应上面自定义方法的 @RequestMapping("/.........")
# 添加任务的URL [选填]:使用调度中心的地址拼接而成,用于向调度中心发送添加任务的请求。
addUrl: ${xxl.job.admin.addresses}/jobinfo/addJob
# 移除任务的URL [选填]:使用调度中心的地址拼接而成,用于向调度中心发送移除任务的请求。
removeUrl: ${xxl.job.admin.addresses}/jobinfo/removeJob
# 启动任务的URL [选填]:使用调度中心的地址拼接而成,用于向调度中心发送启动任务的请求。
startJobUrl: ${xxl.job.admin.addresses}/jobinfo/startJob
# 停止任务的URL [选填]:使用调度中心的地址拼接而成,用于向调度中心发送停止任务的请求。
stopJobUrl: ${xxl.job.admin.addresses}/jobinfo/stopJob
# 添加并立即启动任务的URL [选填]:使用调度中心的地址拼接而成,用于向调度中心发送添加任务并立即启动的请求。
addAndStartUrl: ${xxl.job.admin.addresses}/jobinfo/addAndStartJob
3 配置XxlJobClientConfig
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "xxl.job.client")
public class XxlJobClientConfig {
private Integer jobGroupId;
private String addUrl;
private String removeUrl;
private String startJobUrl;
private String stopJobUrl;
private String addAndStartUrl;
}
4 配置XxlJobClient
/**
* XXL-JOB 客户端类,用于与调度中心进行交互
* 参考文档: https://dandelioncloud.cn/article/details/1598865461087518722
*/
@Slf4j
@Component
public class XxlJobClient {
@Autowired
private XxlJobClientConfig xxlJobClientConfig; // 注入 XXL-JOB 客户端配置
@Autowired
private RestTemplate restTemplate; // 注入 HTTP 请求模板
/**
* 添加一个新的任务
*
* @param executorHandler 任务处理器
* @param param 任务参数
* @param corn 定时表达式
* @param desc 任务描述
* @return 新增任务的 ID
*/
@SneakyThrows
public Long addJob(String executorHandler, String param, String corn, String desc) {
XxlJobInfo xxlJobInfo = new XxlJobInfo(); // 创建任务信息对象
xxlJobInfo.setJobGroup(xxlJobClientConfig.getJobGroupId()); // 设置任务组 ID
xxlJobInfo.setJobDesc(desc); // 设置任务描述
xxlJobInfo.setAuthor("qy"); // 设置任务创建者
xxlJobInfo.setScheduleType("CRON"); // 设置调度类型为 CRON
xxlJobInfo.setScheduleConf(corn); // 设置定时表达式
xxlJobInfo.setGlueType("BEAN"); // 设置任务类型为 BEAN
xxlJobInfo.setExecutorHandler(executorHandler); // 设置任务处理器
xxlJobInfo.setExecutorParam(param); // 设置任务参数
xxlJobInfo.setExecutorRouteStrategy("FIRST"); // 设置路由策略为 FIRST
xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION"); // 设置阻塞策略为 SERIAL_EXECUTION
xxlJobInfo.setMisfireStrategy("FIRE_ONCE_NOW"); // 设置错过策略为 FIRE_ONCE_NOW
xxlJobInfo.setExecutorTimeout(0); // 设置超时时间为 0(永不超时)
xxlJobInfo.setExecutorFailRetryCount(0); // 设置失败重试次数为 0
HttpHeaders headers = new HttpHeaders(); // 创建 HTTP 头
headers.setContentType(MediaType.APPLICATION_JSON); // 设置内容类型为 JSON
HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers); // 创建 HTTP 请求实体
String url = xxlJobClientConfig.getAddUrl(); // 获取添加任务的 URL
ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class); // 发送 POST 请求
if (response.getStatusCode().value() == 200 && response.getBody().getIntValue("code") == 200) {
log.info("增加xxl执行任务成功,返回信息:{}", response.getBody().toJSONString()); // 记录成功日志
// content 为任务 ID
return response.getBody().getLong("content");
}
log.info("调用xxl增加执行任务失败:{}", response.getBody().toJSONString()); // 记录失败日志
throw new MyException(ResultCodeEnum.XXL_JOB_ERROR); // 抛出异常
}
/**
* 启动一个已存在的任务
*
* @param jobId 任务 ID
* @return 操作是否成功
*/
public Boolean startJob(Long jobId) {
XxlJobInfo xxlJobInfo = new XxlJobInfo(); // 创建任务信息对象
xxlJobInfo.setId(jobId.intValue()); // 设置任务 ID
HttpHeaders headers = new HttpHeaders(); // 创建 HTTP 头
headers.setContentType(MediaType.APPLICATION_JSON); // 设置内容类型为 JSON
HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers); // 创建 HTTP 请求实体
String url = xxlJobClientConfig.getStartJobUrl(); // 获取启动任务的 URL
ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class); // 发送 POST 请求
if (response.getStatusCode().value() == 200 && response.getBody().getIntValue("code") == 200) {
log.info("启动xxl执行任务成功:{},返回信息:{}", jobId, response.getBody().toJSONString()); // 记录成功日志
return true;
}
log.info("启动xxl执行任务失败:{},返回信息:{}", jobId, response.getBody().toJSONString()); // 记录失败日志
throw new MyException(ResultCodeEnum.XXL_JOB_ERROR); // 抛出异常
}
/**
* 停止一个已存在的任务
*
* @param jobId 任务 ID
* @return 操作是否成功
*/
public Boolean stopJob(Long jobId) {
XxlJobInfo xxlJobInfo = new XxlJobInfo(); // 创建任务信息对象
xxlJobInfo.setId(jobId.intValue()); // 设置任务 ID
HttpHeaders headers = new HttpHeaders(); // 创建 HTTP 头
headers.setContentType(MediaType.APPLICATION_JSON); // 设置内容类型为 JSON
HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers); // 创建 HTTP 请求实体
String url = xxlJobClientConfig.getStopJobUrl(); // 获取停止任务的 URL
ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class); // 发送 POST 请求
if (response.getStatusCode().value() == 200 && response.getBody().getIntValue("code") == 200) {
log.info("停止xxl执行任务成功:{},返回信息:{}", jobId, response.getBody().toJSONString()); // 记录成功日志
return true;
}
log.info("停止xxl执行任务失败:{},返回信息:{}", jobId, response.getBody().toJSONString()); // 记录失败日志
throw new MyException(ResultCodeEnum.XXL_JOB_ERROR); // 抛出异常
}
/**
* 删除一个已存在的任务
*
* @param jobId 任务 ID
* @return 操作是否成功
*/
public Boolean removeJob(Long jobId) {
XxlJobInfo xxlJobInfo = new XxlJobInfo(); // 创建任务信息对象
xxlJobInfo.setId(jobId.intValue()); // 设置任务 ID
HttpHeaders headers = new HttpHeaders(); // 创建 HTTP 头
headers.setContentType(MediaType.APPLICATION_JSON); // 设置内容类型为 JSON
HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers); // 创建 HTTP 请求实体
String url = xxlJobClientConfig.getRemoveUrl(); // 获取删除任务的 URL
ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class); // 发送 POST 请求
if (response.getStatusCode().value() == 200 && response.getBody().getIntValue("code") == 200) {
log.info("删除xxl执行任务成功:{},返回信息:{}", jobId, response.getBody().toJSONString()); // 记录成功日志
return true;
}
log.info("删除xxl执行任务失败:{},返回信息:{}", jobId, response.getBody().toJSONString()); // 记录失败日志
throw new MyException(ResultCodeEnum.XXL_JOB_ERROR); // 抛出异常
}
/**
* 添加并立即启动一个新的任务
*
* @param executorHandler 任务处理器
* @param param 任务参数
* @param corn 定时表达式
* @param desc 任务描述
* @return 新增任务的 ID
*/
public Long addAndStart(String executorHandler, String param, String corn, String desc) {
XxlJobInfo xxlJobInfo = new XxlJobInfo(); // 创建任务信息对象
xxlJobInfo.setJobGroup(xxlJobClientConfig.getJobGroupId()); // 设置任务组 ID
xxlJobInfo.setJobDesc(desc); // 设置任务描述
xxlJobInfo.setAuthor("qy"); // 设置任务创建者
xxlJobInfo.setScheduleType("CRON"); // 设置调度类型为 CRON
xxlJobInfo.setScheduleConf(corn); // 设置定时表达式
xxlJobInfo.setGlueType("BEAN"); // 设置任务类型为 BEAN
xxlJobInfo.setExecutorHandler(executorHandler); // 设置任务处理器
xxlJobInfo.setExecutorParam(param); // 设置任务参数
xxlJobInfo.setExecutorRouteStrategy("FIRST"); // 设置路由策略为 FIRST
xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION"); // 设置阻塞策略为 SERIAL_EXECUTION
xxlJobInfo.setMisfireStrategy("FIRE_ONCE_NOW"); // 设置错过策略为 FIRE_ONCE_NOW
xxlJobInfo.setExecutorTimeout(0); // 设置超时时间为 0(永不超时)
xxlJobInfo.setExecutorFailRetryCount(0); // 设置失败重试次数为 0
HttpHeaders headers = new HttpHeaders(); // 创建 HTTP 头
headers.setContentType(MediaType.APPLICATION_JSON); // 设置内容类型为 JSON
HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers); // 创建 HTTP 请求实体
String url = xxlJobClientConfig.getAddAndStartUrl(); // 获取添加并启动任务的 URL
ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class); // 发送 POST 请求
if (response.getStatusCode().value() == 200 && response.getBody().getIntValue("code") == 200) {
log.info("增加并开始执行xxl任务成功,返回信息:{}", response.getBody().toJSONString()); // 记录成功日志
// content 为任务 ID
return response.getBody().getLong("content");
}
log.info("增加并开始执行xxl任务失败:{}", response.getBody().toJSONString()); // 记录失败日志
throw new MyException(ResultCodeEnum.XXL_JOB_ERROR); // 抛出异常
}
}
5 启动类配置RestTemplate
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
6 添加并启动任务接口
微服务接口
NewTaskController
@Autowired
private NewTaskService newTaskService;
@Operation(summary = "添加并开始新订单任务调度")
@PostMapping("/addAndStartTask")
public Result<Long> addAndStartTask(@RequestBody NewTaskVo newTaskVo) {
return Result.ok(newTaskService.addAndStartTask(newTaskVo));
}
NewTaskService
void addAndStartTask(NewTaskVo newTaskVo);
NewTaskServiceImpl
public class OrderTaskService extends ServiceImpl<OrderJobMapper, OrderJob> {
@Autowired
private XxlJobClient xxlJobClient; // 注入 XXL-JOB 客户端
@Autowired
private OrderJobMapper orderJobMapper; // 注入订单任务映射器
/**
* 添加并启动一个新任务
*
* @param NewTaskVo 新订单任务的视图对象
* @return 任务 ID
*/
@Transactional(rollbackFor = Exception.class) // 开启事务管理,遇到异常时回滚事务
@Override
public void addAndStartTask(NewTaskVo NewTaskVo) {
// 添加并启动一个新的任务
Long jobId = xxlJobClient.addAndStart(
"newOrderTaskHandler", // 任务处理器
"", // 任务参数
"0 0/1 * * * ?", // 定时表达式,每分钟执行一次
"新订单任务,订单id:" + NewTaskVo.getOrderId() // 任务描述
);
}
}
说明:每1分钟执行一次,处理任务的bean为:newOrderTaskHandler
7 开发任务Job方法
@Component
public class JobHandler {
@XxlJob("newOrderTaskHandler")
public void newOrderTaskHandler() {
//执行业务
}
}
```java
vice extends ServiceImpl<OrderJobMapper, OrderJob> {
@Autowired
private XxlJobClient xxlJobClient; // 注入 XXL-JOB 客户端
@Autowired
private OrderJobMapper orderJobMapper; // 注入订单任务映射器
/**
* 添加并启动一个新任务
*
* @param NewTaskVo 新订单任务的视图对象
* @return 任务 ID
*/
@Transactional(rollbackFor = Exception.class) // 开启事务管理,遇到异常时回滚事务
@Override
public void addAndStartTask(NewTaskVo NewTaskVo) {
// 添加并启动一个新的任务
Long jobId = xxlJobClient.addAndStart(
"newOrderTaskHandler", // 任务处理器
"", // 任务参数
"0 0/1 * * * ?", // 定时表达式,每分钟执行一次
"新订单任务,订单id:" + NewTaskVo.getOrderId() // 任务描述
);
}
}
说明:每1分钟执行一次,处理任务的bean为:newOrderTaskHandler
7 开发任务Job方法
@Component
public class JobHandler {
@XxlJob("newOrderTaskHandler")
public void newOrderTaskHandler() {
//执行业务
}
}
完成!
标签:执行器,spring,xxlJobInfo,job,动态创建,JOB,任务,任务调度,xxl From: https://blog.csdn.net/2301_81717523/article/details/142897188