SpringBoot使用xxl-job管理定时任务

Sabthever

  在部署高可用后端代码的过程中,发现多节点的定时任务会执行多次,导致一些顺序上的错误,这时候就需要一个中央程序来进行定时任务管理。

一. 问题

  上述是我实际遇到的问题,后端部署了K8S多节点高可用的程序,但是用Springboot原生的@Scheduled会导致每一个节点中执行重复的定时任务。每一个定时任务的数据计算量都是比较大的,而且还有多个这样的定时任务,所以不同节点同时执行还会导致顺序上的问题。

  这时候就需要一个能够管理多节点的程序。

二. xxl-job使用场景

1、需要分布式调度能力时

场景:

  • 你的 Spring Boot 应用部署在 多个实例 / 多台服务器上(即集群部署),但某些任务 只能由一个节点执行一次,避免重复执行。

为什么用 xxl-job:

  • xxl-job 提供了 分布式任务调度 能力,通过调度中心统一管理和触发任务,可以确保 同一个任务在分布式环境下只被执行一次,避免多实例造成的任务重复。

2、任务需要可视化管理和运维

场景:

  • 你希望有一个 Web 管理界面,可以方便地查看、新增、修改、启动/停止、监控定时任务,而不想手动改代码或者维护 Cron 表达式。

为什么用 xxl-job:

  • xxl-job 提供了功能完善的 后台管理界面,支持:任务的增删改查Cron 表达式配置任务运行日志查看任务执行结果监控任务失败告警等
  • 相比于 Spring 自带的 @Scheduled注解方式,xxl-job 更加灵活和便于管理,特别是在生产环境中。

3、任务调度的动态调整需求频繁

场景:

  • 你希望 不重启服务 就能 动态修改任务的执行时间、执行策略、启停状态

为什么用 xxl-job:

  • 在 Spring Boot 原生方式下(如 @Scheduled),一旦应用启动,Cron 表达式就固定了,要修改必须重新部署。
  • xxl-job 支持 在线动态修改任务配置,无需重启应用,极大提升了灵活性和可维护性。

4、任务执行需要失败重试、报警机制

场景:

  • 某些定时任务非常重要,如果执行失败,你希望能够 自动重试 或者 及时通知相关人员(如邮件、短信、钉钉等)。

为什么用 xxl-job:

  • xxl-job 提供了:任务失败重试机制任务执行结果监控灵活的失败告警策略(支持多种通知方式)
  • 可以大大增强定时任务的可靠性与可观测性。

5、任务之间有依赖关系或需要分片并行处理

场景:

  • 你有一些大数据量处理任务,希望把任务 分片并行处理(比如按地区、ID范围拆分后多节点并发执行)。
  • 或者多个任务之间存在 依赖关系,需要按顺序调度。

为什么用 xxl-job:

  • xxl-job 支持:任务分片广播:将一个任务拆分成多个子任务,分配给不同节点并发执行,提高效率。任务依赖:可以配置任务之间的依赖关系,实现调度链。
  • 这对于 大数据处理、批量任务、报表生成等场景 非常有用。

6、微服务架构下的统一调度管理

场景:

  • 你的系统已经采用 Spring Cloud / 微服务架构,多个服务都可能有自己的定时任务,你希望对这些任务进行 统一调度、统一管理、集中监控

为什么用 xxl-job:

  • xxl-job 可以作为 统一的调度中心,接入各个微服务中的应用,让不同服务的定时任务都由调度中心触发,避免每个服务自己维护调度逻辑,提升整体可维护性与一致性。

三. 对比总结

特性 Spring @Scheduled xxl-job
调度方式 应用内定时器,单机控制 分布式调度,由调度中心统一管理
分布式支持 不支持,多实例可能重复执行 支持,确保任务只执行一次
动态调整 不支持,需改代码重启 支持,可在线修改任务配置
管理界面 无,需自行开发 提供完善的后台管理界面
任务监控 无,需自行实现 提供任务执行日志、状态、失败告警等
任务分片/依赖 不支持 支持任务分片、任务依赖
适用场景 简单、单机、低频率任务 分布式、生产级、高可靠定时任务

什么时候不用xxl-job

以下情况下用Springboot自带的@Scheduled可能就够了:

  • 项目是 单体应用,单实例部署
  • 定时任务非常 简单,执行频率低,重要性不高
  • 没有 分布式调度、动态管理、监控报警 等高级需求
  • 希望 轻量级、零依赖、快速开发

四. xxl-job安装部署

有容器化部署和手动部署两种方式,但是不论哪一种,都需要有mysql数据库作为信息的存储。

具体的部署方式可以参考文章xxl-job与其他调度框架比较与部署

默认账号密码:admin/123456登录

五. xxl-job在Springboot中的使用

下面以xxl-job-admin-2.4.0为例,进行讲解。

1.Springboot所需依赖

在相应pom里面加入

1
2
3
4
5
6
<!-- XXL-JOB 核心依赖:执行器与调度中心通信、注解、线程池等都在这里 -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${xxl-job.version}</version>
</dependency>

${xxl-job.version}需要使用对应的xxl-job版本号

2.Springboot配置文件

配置文件中,需要配置xxl-job服务器地址以及执行器地址。执行器的地址,实际上就是当前后端的地址,ip实际上不用配置,会直接获取本机地址,主要吧执行器的端口配置好。

1
2
3
4
5
6
7
8
9
10
11
12
#xxl-job
xxl:
job:
admin:
addresses: http://10.247.190.226:28080/xxl-job-admin
executor:
appname: ability-executor-test
ip:
port: 9010
logpath: xxl-job/log
logretentiondays: 30
accessToken: default_token

3.Springboot容器注册文件

要在文件中配置Spring单例Bean,需要编写一个配置单java文件。

这样一旦 Spring 容器启动,执行器就通过该 Bean 完成向 XXL-JOB-Admin 的“心跳注册”,后续才能接收到调度中心派发的任务指令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.cockpit.web.xxljob.config;


import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class XxlJobConfig {


@Value("${xxl.job.admin.addresses}")
private String adminAddresses;

@Value("${xxl.job.executor.appname}")
private String appName;

@Value("${xxl.job.executor.ip}")
private String ip;

@Value("${xxl.job.executor.port}")
private int port;

@Value("${xxl.job.accessToken}")
private String accessToken;

@Value("${xxl.job.executor.logpath}")
private String logPath;

@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;


@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
log.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appName);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
}

4.Springboot业务逻辑文件

  • 写真正的定时任务业务逻辑,一个 @XxlJob 方法对应控制台里配置的一个“JobHandler”名称;
  • 当调度中心触发对应任务时,XXL-JOB 会找到这个 Bean 方法并在线程池中执行;
  • 方法返回 ReturnT 或 void 均可,内部可自由注入 Spring 的任何 Service、Mapper 等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.cockpit.web.xxljob.handler;

import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class TaskHandler {
@XxlJob("test01Handler")
public void test01Handler() {
XxlJobHelper.log("hello,00000000000000000");
log.error("====test01Handler============>执行");
XxlJobHelper.log("hello,11111111111111111");
XxlJobHelper.log("hello,00000000000000000");
}
}

5.xxl-job配置执行器

首先,对于我之前遇到的问题,是个这样的情况,有三个后端程序同时在运行,使用原生Scheduled就会执行三遍。在使用xxl-job的时候相当于是三个执行器,如果没有负载均衡的nginx的话,执行器需要配置三个地址。

image-20251111153604718

进入到xxl-job任务调度中心 - 执行器管理 - 新增,然后填写相应的配置。

image-20251111163641638

如果没有负载均衡而是三个独立的执行器,则在机器地址里配置相应的ip和端口,各个地址间用,隔开。

6.xxl-job配置任务

进入到xxl-job任务调度中心 - 任务管理 - 新增,然后填写相应的配置。如下图所示:

image-20251111164423204

执行器器要选择刚才我们配制好的,调度类型选择cron,配置相应的corn表达式。JobHandler中就要填写代码里面@XxlJob("xx")里面填写的handler名。其他高级配置根据需求进行选择,我这边路由策略倾向于故障转移,这样会自动选择好的节点调度。

六. 总结

K8s 多副本场景下,Spring 自带的 @Scheduled 会导致每个 Pod 同时触发同一任务。接入xxl-job 后,由调度中心统一路由,保证“同一个任务、同一时刻、只被一个节点执行”,彻底解决重复计算与数据错乱问题。

并且,在需要手动执行该定时任务时,也无需增加多余的接口,只要在任务管理中“执行一次”即可。

  • 标题: SpringBoot使用xxl-job管理定时任务
  • 作者: Sabthever
  • 创建于 : 2025-10-29 13:22:46
  • 更新于 : 2025-11-11 19:42:11
  • 链接: https://sabthever.cn/2025/10/29/technology/java/SpringBoot使用xxl-job管理定时任务/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。