本文目录导读:

我来为您详细介绍XXL-JOB的实战案例,从基础到进阶,覆盖常见业务场景。
XXL-JOB基础介绍
XXL-JOB是一个分布式任务调度平台,核心特点:
- 简单易用(通过Web页面管理任务)
- 动态定时任务(支持CRON表达式)
- 分布式调度(支持集群部署)
- 失败重试机制
- 任务分片处理
环境搭建案例
调度中心部署
-- 初始化数据库(执行官方提供的SQL脚本) xxl_job.sql -- 修改配置文件 application.properties server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8 spring.datasource.username=root spring.datasource.password=root
执行器接入SpringBoot
<!-- pom.xml 引入依赖 -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.4.0</version>
</dependency>
# application.yml
xxl:
job:
admin:
addresses: http://localhost:8080/xxl-job-admin
executor:
appname: xxl-job-executor-sample
ip:
port: 9999
logpath: /data/applogs/xxl-job/jobhandler
logretentiondays: 30
// 执行器配置类
@Configuration
public class XxlJobConfig {
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.executor.appname}")
private String appName;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appName);
xxlJobSpringExecutor.setPort(9999);
xxlJobSpringExecutor.setLogPath("/data/applogs/xxl-job/jobhandler");
return xxlJobSpringExecutor;
}
}
实战案例
案例1:报表定时生成
业务场景:每天凌晨2点生成前一天的销售报表
@Component
public class ReportJobHandler {
@Resource
private SalesReportService reportService;
@Resource
private EmailService emailService;
@XxlJob("dailySalesReportJob")
public void dailySalesReport() throws Exception {
// 获取任务参数(调度中心配置)
String jobParam = XxlJobHelper.getJobParam();
// 1. 获取前一天日期
String yesterday = LocalDate.now().minusDays(1)
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
// 2. 查询销售数据
List<SalesData> salesDataList = reportService.getDailySales(yesterday);
// 3. 生成Excel报表
Workbook workbook = ExcelGenerator.generateSalesReport(salesDataList);
// 4. 发送邮件
String[] receivers = {"manager@company.com", "finance@company.com"};
emailService.sendReportEmail(receivers,
"业务报表-" + yesterday, workbook);
// 5. 记录日志
XxlJobHelper.log("报表生成成功,数据量:{}", salesDataList.size());
}
}
案例2:订单超时处理(分片任务)
业务场景:每5分钟处理超时未支付的订单,使用分片提高效率
@Component
public class OrderTimeoutJobHandler {
@Resource
private OrderService orderService;
@XxlJob("orderTimeoutHandleJob")
public void handleTimeoutOrders() {
// 获取分片参数
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
XxlJobHelper.log("开始处理超时订单,分片:{}/{}",
shardIndex, shardTotal);
// 根据分片查询需要处理的订单
// WHERE MOD(order_id, shardTotal) = shardIndex
List<Order> timeoutOrders = orderService
.getTimeoutOrdersForShard(shardIndex, shardTotal);
for (Order order : timeoutOrders) {
try {
// 处理订单超时
orderService.handleTimeoutOrder(order.getId());
} catch (Exception e) {
XxlJobHelper.log("订单{}处理失败:{}",
order.getId(), e.getMessage());
}
}
XxlJobHelper.log("分片{}处理完成,共处理{}个订单",
shardIndex, timeoutOrders.size());
}
}
案例3:数据同步任务
业务场景:同步用户数据到搜索引擎
@Component
public class DataSyncJobHandler {
@Resource
private UserService userService;
@Resource
private ElasticSearchService esService;
@XxlJob("userDataSyncJob")
public void syncUserData() {
// 获取增量同步游标
String cursor = getLastSyncCursor();
// 批量查询增量用户数据
List<User> users = userService.getIncrementalUsers(cursor);
if (users.isEmpty()) {
XxlJobHelper.log("无增量数据需要同步");
return;
}
// 批量同步到ES
esService.bulkUpsertUsers(users);
// 记录增量同步游标
String lastUserId = users.get(users.size() - 1).getId();
saveLastSyncCursor(lastUserId);
XxlJobHelper.log("数据同步完成,同步用户数:{}", users.size());
}
}
案例4:动态参数任务
业务场景:灵活执行数据清理任务,通过参数控制
@Component
public class DataCleanJobHandler {
@XxlJob("dataCleanJob")
public void cleanData() {
// 从调度中心获取任务参数
String jobParam = XxlJobHelper.getJobParam();
// 解析任务参数:{"days":30,"table":"log","batchSize":1000}
JSONObject paramObj = JSONObject.parseObject(jobParam);
int days = paramObj.getIntValue("days");
String table = paramObj.getString("table");
int batchSize = paramObj.getIntValue("batchSize");
// 计算清理截止时间
Date deadline = DateTime.now()
.minusDays(days)
.toDate();
int deletedCount = 0;
while (true) {
// 分批清理数据
boolean success = dataCleanService.cleanOldData(
table, deadline, batchSize);
if (success) {
deletedCount += batchSize;
// 防止任务执行时间过长
if (XxlJobHelper.getJobDuration() > 300000) {
XxlJobHelper.log("任务执行超时,提前结束");
break;
}
} else {
break;
}
}
XxlJobHelper.log("数据清理完成,共清理{}条数据", deletedCount);
}
}
案例5:任务阻塞和失败处理
@Component
public class ComplexJobHandler {
@XxlJob("complexJob")
public ReturnT<String> complexTask(String param) {
try {
// 业务处理前检查
if (!checkPreConditions()) {
return new ReturnT<>(ReturnT.FAIL_CODE,
"前置条件不满足,终止执行");
}
// 业务处理
doBusinessLogic();
// 可以通过抛出异常触发失败重试
// throw new RuntimeException("模拟任务失败");
return ReturnT.SUCCESS;
} catch (Exception e) {
XxlJobHelper.log("任务执行异常:{}", e);
// 失败重试最多3次
if (XxlJobHelper.getJobResult().getRetryCount() < 3) {
return new ReturnT<>(ReturnT.FAIL_RETRY_CODE,
"执行失败,等待重试");
}
return new ReturnT<>(ReturnT.FAIL_CODE,
"执行失败,超过重试次数");
}
}
private void doBusinessLogic() {
// 模拟业务处理
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
案例6:父子任务处理
业务场景:数据同步完成后再执行数据分析
@Component
public class ParentChildJobHandler {
@Resource
private JobClientUtils jobClientUtils;
// 父任务
@XxlJob("parentSyncJob")
public void parentJob() {
// 1. 执行数据同步
syncData();
// 2. 动态触发子任务
try {
jobClientUtils.triggerChildJob("childAnalyzeJob",
"syncData_completed", 1000);
} catch (Exception e) {
XxlJobHelper.log("触发子任务失败:{}", e);
}
}
@JobHandler("childAnalyzeJob")
public void childJob() {
// 执行数据分析
}
}
案例7:库存扣减任务
@Component
public class InventoryJobHandler {
@Resource
private InventoryService inventoryService;
@XxlJob("inventoryDailyCheckJob")
public void dailyInventoryCheck() {
XxlJobHelper.log("=== 库存日结任务开始 ===");
try {
// 1. 获取所有库存
List<Inventory> inventories = inventoryService.getAllInventory();
// 2. 生成库存快照
boolean snapshotSuccess = inventoryService.createInventorySnapshot();
// 3. 库存预警检查
List<String> warningProducts = new ArrayList<>();
for (Inventory inv : inventories) {
if (inv.getStock() < inv.getWarningThreshold()) {
warningProducts.add(inv.getProductId());
}
}
// 4. 发送预警通知
if (!warningProducts.isEmpty()) {
sendStockWarningEmail(warningProducts);
}
XxlJobHelper.log("=== 库存日结任务完成,预警商品数:{} ===",
warningProducts.size());
} catch (Exception e) {
XxlJobHelper.log("库存日结任务失败:{}", e);
throw new RuntimeException("库存日结失败", e);
}
}
}
最佳实践建议
调度中心配置参数
- 阻塞处理策略:建议使用"丢弃后续调度"
- 失败重试次数:建议2-3次
- 日志保留天数:建议7-30天
任务开发规范
@XxlJob("yourJobName") // 任务名称要规范,使用驼峰命名
public void yourJob() {
// 1. 记录任务开始
XxlJobHelper.log("任务开始执行");
// 2. 获取参数(如果有)
String param = XxlJobHelper.getJobParam();
// 3. 业务处理
try {
// 业务逻辑
} catch (Exception e) {
// 4. 异常处理
XxlJobHelper.log("任务执行异常:{}", e);
throw e; // 让调度中心知道任务失败
}
// 5. 记录任务结束
XxlJobHelper.log("任务执行成功");
}
性能优化建议
- 大数据量任务使用分片
- 耗时操作异步处理
- 批量操作设置合理批次大小
- 避免任务执行时间过长(建议不超过10分钟)
监控告警建议
- 配置任务失败告警邮件/短信
- 定期检查执行器健康状态
- 设置合理的任务执行超时时间
- 监控调度中心负载情况
这些案例涵盖了XXL-JOB的主要使用场景,希望能帮助您更好地理解和使用XXL-JOB,记得根据实际业务需求调整和完善相关实现。