sh-xxljob
XXL-Job 分布式定时任务集成模块
sh-xxljob 是 sh-framework 的 XXL-Job 分布式定时任务集成模块,为应用提供开箱即用的执行器自动配置。该模块基于 xxl-job-core(3.4.0)实现,简化了分布式定时任务的集成工作,支持 @XxlJob 注解开发任务处理器。
模块概述
核心价值
- 开箱即用:自动配置,最小化配置工作
- 智能默认:
appName默认使用spring.application.name - 完整集成:支持所有 XXL-Job 标准功能
- 企业级特性:支持集群部署、日志管理、安全认证
主要特性
- 自动配置:Spring Boot 自动配置,无需手动配置
- 智能默认:
appName自动使用应用名称 - 完整支持:支持所有 XXL-Job 标准配置项
- 示例代码:内置示例任务处理器
- 日志管理:支持任务日志存储和清理
- 集群支持:支持多执行器集群部署
快速开始
1. 添加依赖
在项目的 pom.xml 文件中添加 sh-xxljob 依赖:
<dependency>
<groupId>com.wkclz.framework</groupId>
<artifactId>sh-xxljob</artifactId>
<version>${sh-framework.version}</version>
</dependency>2. 配置 XXL-Job 调度中心
在 application.yml 中配置 XXL-Job 调度中心连接信息:
xxl:
job:
admin:
addresses: http://xxl-job-admin:8080/xxl-job-admin
accessToken: your-token # 可选,调度中心通讯令牌
executor:
appname: ${spring.application.name} # 自动使用应用名称
port: 9999
logpath: ./xxl-job/jobhandler
logretentiondays: 303. 自动配置
sh-xxljob 通过 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 自动注册,由 XxlJobAutoConfigure 自动扫描并注册相关组件:
@AutoConfiguration
@ComponentScan(basePackages = {"com.wkclz.xxljob"})
public class XxlJobAutoConfigure {
}核心组件
1. XxlJobConfig - 执行器配置类
XxlJobConfig(@Component)读取 XXL-Job 执行器配置并创建 XxlJobSpringExecutor Bean(xxlJobExecutor())。
配置项说明
| 配置键 | 默认值 | 说明 |
|---|---|---|
xxl.job.admin.addresses | 空 | 调度中心地址(集群逗号分隔;空则关闭自动注册) |
xxl.job.admin.accessToken | 空 | 通讯令牌,非空时启用 |
xxl.job.admin.timeout | 3 | 调度中心通讯超时时间(秒) |
xxl.job.executor.appname | ${spring.application.name} | 执行器 AppName(心跳注册分组依据) |
xxl.job.executor.address | 空 | 执行器注册地址(优先使用,空则自动 IP:PORT) |
xxl.job.executor.ip | 空 | 执行器 IP(多网卡时可手动设置) |
xxl.job.executor.port | 9999 | 执行器端口号(小于等于 0 则自动获取;多执行器需不同端口) |
xxl.job.executor.logpath | ./xxl-job/jobhandler | 执行器运行日志文件存储磁盘路径 |
xxl.job.executor.logretentiondays | 30 | 执行器日志文件保存天数(≥3 生效,-1 关闭清理) |
核心 Bean 创建
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
log.info(">>>>>>>>>>> xxl-job config init {} to {}", appName, adminAddresses);
XxlJobSpringExecutor executor = new XxlJobSpringExecutor();
executor.setAdminAddresses(adminAddresses);
executor.setAppname(appName);
executor.setTimeout(timeout);
executor.setAddress(address);
executor.setIp(ip);
executor.setPort(port);
executor.setAccessToken(accessToken);
executor.setLogPath(logPath);
executor.setLogRetentionDays(logRetentionDays);
return executor;
}2. 编写 Job Handler
xxl-job 3.4.0 推荐使用 XxlJobHelper 进行日志记录、参数获取、分片处理与结果上报;任务方法返回 void,执行结果通过 handleSuccess / handleFail / handleResult 显式上报,方法抛出异常同样视为失败。
基本示例
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
@Component
public class MyJobHandler {
@XxlJob("myBusinessJob")
public void myBusinessJob() {
XxlJobHelper.log("开始执行业务任务...");
// 业务逻辑
try {
processBusinessLogic();
XxlJobHelper.log("业务任务执行完成");
} catch (Exception e) {
XxlJobHelper.log("业务任务执行失败: " + e.getMessage());
throw e; // 抛异常表示任务失败
}
}
private void processBusinessLogic() {
// 具体的业务逻辑
}
}带参数的 Job Handler
@Component
public class ParameterizedJobHandler {
@XxlJob("parameterizedJob")
public void parameterizedJob() {
// 获取任务参数
String jobParam = XxlJobHelper.getJobParam();
XxlJobHelper.log("任务参数: " + jobParam);
// 获取分片参数
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
XxlJobHelper.log("分片参数: {}/{}", shardIndex, shardTotal);
// 根据分片参数处理数据
processDataByShard(shardIndex, shardTotal, jobParam);
}
private void processDataByShard(int shardIndex, int shardTotal, String param) {
// 根据分片处理数据
// 例如:处理数据库中的某一部分数据
}
}手动上报执行结果
@XxlJob("resultJob")
public void resultJob() {
try {
// 业务逻辑
boolean success = executeBusinessLogic();
if (success) {
XxlJobHelper.handleSuccess("执行成功");
} else {
XxlJobHelper.handleFail("业务执行未成功");
}
} catch (Exception e) {
XxlJobHelper.log("执行异常: {}", e.getMessage());
XxlJobHelper.handleFail(e.getMessage());
throw e;
}
}3. XxlJobDemo - 示例任务处理器
sh-xxljob 模块内置了一个示例任务处理器:
@Component
public class XxlJobDemo {
@XxlJob("demoJobHandler")
public void demoJobHandler() {
XxlJobHelper.log("XXL-JOB, Hello World.");
}
}注意:这个示例会自动注册,如果不需要,可以通过以下方式排除:
- 移除
@Component注解 - 在配置中排除扫描
com.wkclz.xxljob.demo包
详细配置指南
1. 最小配置
只需要配置调度中心地址即可运行:
xxl:
job:
admin:
addresses: http://localhost:8080/xxl-job-admin2. 完整配置示例
xxl:
job:
admin:
addresses: http://xxl-job-admin-1:8080/xxl-job-admin,http://xxl-job-admin-2:8080/xxl-job-admin
accessToken: your-secret-token
timeout: 5
executor:
appname: order-service
address:
ip: 192.168.1.100
port: 9999
logpath: /data/logs/xxl-job/order-service
logretentiondays: 303. 多环境配置
# application-dev.yml (开发环境)
xxl:
job:
admin:
addresses: http://dev-xxl-job:8080/xxl-job-admin
executor:
appname: ${spring.application.name}
port: 9999
# application-prod.yml (生产环境)
xxl:
job:
admin:
addresses: http://prod-xxl-job-1:8080/xxl-job-admin,http://prod-xxl-job-2:8080/xxl-job-admin
accessToken: ${XXL_JOB_ACCESS_TOKEN}
executor:
appname: ${spring.application.name}
port: 9999
logpath: /var/log/xxl-job/${spring.application.name}
logretentiondays: 90使用示例
1. 数据同步任务
@Component
public class DataSyncJobHandler {
@Autowired
private UserService userService;
@Autowired
private OrderService orderService;
@XxlJob("syncUserData")
public void syncUserData() {
XxlJobHelper.log("开始同步用户数据");
// 同步用户数据
int count = userService.syncFromExternalSystem();
XxlJobHelper.log("成功同步 {} 条用户数据", count);
// 执行失败时抛出异常即可标记任务失败
}
@XxlJob("syncOrderData")
public void syncOrderData() {
XxlJobHelper.log("开始同步订单数据");
// 获取分片参数,实现分布式处理
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
// 根据分片处理订单数据
orderService.syncOrdersByShard(shardIndex, shardTotal);
XxlJobHelper.log("订单数据同步完成,分片: {}/{}", shardIndex, shardTotal);
}
}2. 报表生成任务
@Component
public class ReportJobHandler {
@Autowired
private ReportService reportService;
@XxlJob("generateDailyReport")
public void generateDailyReport() {
XxlJobHelper.log("开始生成日报表");
// 获取昨天的日期
LocalDate yesterday = LocalDate.now().minusDays(1);
// 生成日报表
ReportResult result = reportService.generateDailyReport(yesterday);
XxlJobHelper.log("日报表生成成功: {}", result);
}
@XxlJob("cleanOldReports")
public void cleanOldReports() {
XxlJobHelper.log("开始清理过期报表");
// 清理30天前的报表
int deletedCount = reportService.cleanOldReports(30);
XxlJobHelper.log("清理完成,共删除 {} 个过期报表", deletedCount);
}
}3. 消息处理任务
@Component
public class MessageJobHandler {
@Autowired
private MessageService messageService;
@XxlJob("processPendingMessages")
public void processPendingMessages() {
XxlJobHelper.log("开始处理待发送消息");
// 获取任务参数(每次处理的消息数量)
String param = XxlJobHelper.getJobParam();
int batchSize = StringUtils.isNotBlank(param) ? Integer.parseInt(param) : 100;
// 处理待发送消息
int processedCount = messageService.processPendingMessages(batchSize);
XxlJobHelper.log("消息处理完成,共处理 {} 条消息", processedCount);
}
@XxlJob("retryFailedMessages")
public void retryFailedMessages() {
XxlJobHelper.log("开始重试失败消息");
int retryCount = messageService.retryFailedMessages();
if (retryCount > 0) {
XxlJobHelper.log("成功重试 {} 条失败消息", retryCount);
} else {
XxlJobHelper.log("没有需要重试的失败消息");
}
}
}最佳实践
1. 任务命名规范
- 使用有意义的任务名称,如
syncUserData、generateDailyReport - 遵循驼峰命名法
- 避免使用特殊字符和空格
2. 日志记录
- 使用
XxlJobHelper.log()记录任务执行日志 - 日志会同步到调度中心,便于查看任务执行情况
- 记录关键步骤和异常信息
3. 异常处理
xxl-job 3.4.0 下任务方法返回 void,执行结果通过 XxlJobHelper 的 handleSuccess / handleFail / handleResult 显式上报,方法抛出异常同样视为失败。推荐在 catch 中记录日志(XxlJobHelper.log(String, Object...) 或 XxlJobHelper.log(Throwable))后重新抛出:
@XxlJob("safeJobHandler")
public void safeJobHandler() {
try {
// 业务逻辑
executeBusinessLogic();
XxlJobHelper.handleSuccess("执行成功");
} catch (BusinessException e) {
// 业务异常,记录日志并标记失败
XxlJobHelper.log("业务异常: {}", e.getMessage());
XxlJobHelper.handleFail(e.getMessage());
throw e;
} catch (Exception e) {
// 系统异常,记录详细日志
XxlJobHelper.log("系统异常: {}", e.getMessage());
XxlJobHelper.log(e);
XxlJobHelper.handleFail("系统异常");
throw e;
}
}4. 性能优化
- 对于大数据量处理,使用分片参数实现分布式处理
- 合理设置任务执行超时时间
- 避免在任务中执行长时间阻塞的操作
5. 监控告警
- 在调度中心配置任务失败告警
- 监控任务执行时间和成功率
- 定期检查任务日志
常见问题
1. 执行器无法注册到调度中心
可能原因:
- 调度中心地址配置错误
- 网络不通
- 调度中心未启动
解决方案:
- 检查
xxl.job.admin.addresses配置是否正确 - 检查网络连接
- 查看执行器日志,确认注册过程
2. 任务执行失败
可能原因:
- 任务处理器不存在或名称不匹配
- 任务代码异常
- 资源不足
解决方案:
- 检查任务处理器名称是否与调度中心配置一致
- 查看任务执行日志
- 检查系统资源使用情况
3. 日志无法查看
可能原因:
- 日志路径配置错误
- 权限不足
- 日志文件被清理
解决方案:
- 检查
xxl.job.executor.logpath配置 - 确保应用有写权限
- 检查
logretentiondays配置
架构原理
自动配置流程
引入 sh-xxljob 依赖
→ 读取 AutoConfiguration.imports
→ 加载 XxlJobAutoConfigure
→ @ComponentScan 扫描 com.wkclz.xxljob 包
→ XxlJobConfig 注册为 Bean
→ xxlJobExecutor() 创建 XxlJobSpringExecutor
→ XxlJobDemo 注册为 Bean(示例 Handler)
→ 执行器启动,向调度中心注册组件交互
调度中心 (XXL-Job Admin)
↑
| HTTP/RPC
↓
执行器 (XxlJobSpringExecutor)
↑
| Spring Bean 调用
↓
任务处理器 (@XxlJob 注解的方法)注意事项
- 配置前缀:使用
xxl.job前缀,与 XXL-Job 官方约定保持一致 - 智能默认:
appname默认使用spring.application.name,无需重复配置 - 最小配置:仅需配置
xxl.job.admin.addresses即可运行 - 示例代码:
XxlJobDemo会自动注册,如不需要可排除 - 日志管理:合理设置
logretentiondays,避免日志文件过多 - 结果判定:xxl-job 3.4.0 已移除
ReturnT,任务方法返回void,通过XxlJobHelper.handleSuccess/handleFail/handleResult或抛异常上报结果
相关链接
通过 sh-xxljob 模块,您可以快速集成 XXL-Job 分布式定时任务系统