
如果你正在为分布式系统中的定时任务管理而头疼或者厌倦了在多个服务中维护一堆零散的Scheduled注解那么今天要聊的 XXL-JOB 配置与调用中心可能就是那个能让你“一劳永逸”的解决方案。很多开发者初次接触 XXL-JOB 时容易把它简单理解为一个“高级版的定时任务框架”。这其实低估了它的核心价值。XXL-JOB 真正的威力在于它通过一个独立的“调度中心”将任务的调度逻辑与业务执行逻辑彻底解耦。这意味着你不再需要在每个微服务里写死 cron 表达式也不再需要担心任务重复执行或失败后无人知晓。它解决的不是“如何定时执行代码”而是“如何高效、可靠、可视化管理成千上万个分散的任务”。本文将聚焦于 XXL-JOB 最核心、也最让新手困惑的部分调度中心与执行器的配置与联调。我会带你从零开始搭建一个完整的 XXL-JOB 环境并深入讲解配置项背后的设计逻辑与最佳实践。读完本文你将能清晰地掌握调度中心与执行器的角色划分与通信原理。如何正确配置数据库、网络、令牌等关键环节避开 80% 的部署坑。编写一个可被远程调度的任务并理解其生命周期。当任务“失联”或执行失败时一套高效的排查思路。我们直接进入正题。1. 为什么需要独立的“调度中心”从单机定时任务到分布式调度的演进在单体应用时代我们使用 Spring 的Scheduled或 Quartz 就能满足大部分定时任务需求。任务和应用绑定在一起开发简单但问题也显而易见资源竞争应用多实例部署时同一任务会被多个实例同时触发可能导致业务逻辑错误如重复扣款。单点故障任务调度逻辑嵌在应用中一旦该实例宕机所有定时任务都会停止。管理困难任务散落在各个代码中没有统一视图无法监控执行状态、手动触发或调整调度策略。弹性差难以根据负载动态分配或迁移任务。XXL-JOB 引入了“中心化调度”的思想其架构非常清晰调度中心Admin一个独立部署的 Web 服务。它负责管理所有任务的调度逻辑何时触发、路由策略发给哪个执行器、监控报警和日志查看。它是大脑负责决策。执行器Executor嵌入在你的业务应用一个或多个中。它负责接收调度中心的指令执行具体的业务逻辑。它是四肢负责干活。两者通过 HTTP/RPC 进行通信。这种解耦带来了巨大优势调度中心可以统一管理所有任务执行器可以水平扩展通过负载均衡执行任务即使某个执行器宕机调度中心也能感知并将任务路由到其他健康实例。理解这个“中心化”模型是正确配置 XXL-JOB 的第一步。2. 核心概念与配置全景图在动手配置前我们需要明确几个关键概念和它们之间的配置关系。概念角色关键配置项说明调度中心 (Admin)任务调度的大脑提供管理界面xxl.job.admin.addresses执行器用来回调调度中心的地址列表。这是联调成功最关键的一环。执行器 (Executor)任务执行的节点嵌入业务应用xxl.job.executor.appname执行器的唯一标识调度中心通过它来识别和管理一组执行器实例。执行器注册地址执行器提供给调度中心的通信地址xxl.job.executor.address通常自动获取ip:port也可手动指定。调度中心通过此地址下发任务触发命令。访问令牌 (AccessToken)调度中心与执行器间的安全凭证xxl.job.accessToken非必填但生产环境强烈建议启用用于验证 HTTP 调用的合法性。任务 (Job)具体的业务逻辑单元XxlJob注解在执行器项目中被此注解标记的方法就是一个可被调度的任务。配置全景图调度端配置主要围绕数据库存储任务元数据和网络地址让执行器能找到自己。执行端配置主要围绕应用名身份ID、网络地址让调度中心能找到自己和调度中心地址知道向谁注册。双向联通执行器启动后会向xxl.job.admin.addresses中配置的调度中心注册自己。调度中心收到任务触发指令后会根据执行器的注册地址将触发请求发送到对应的执行器。最常见的误区以为只需要执行器配置调度中心地址就够了。实际上网络必须是双向可达的。执行器要能访问调度中心用于注册和回调日志调度中心也要能访问执行器用于触发任务。很多部署在 Docker 或内网的环境问题都出在这里。3. 环境准备与前置条件我们将完成一个最小化的本地演示环境。请确保你的开发机已具备以下条件操作系统Windows / macOS / Linux 均可。JavaJDK 1.8 或以上版本。运行java -version确认。Maven3.6 或以上版本。运行mvn -v确认。MySQL5.7 或以上版本。这是 XXL-JOB 调度中心存储任务信息、日志等元数据的数据库。IDEIntelliJ IDEA 或 Eclipse用于导入和运行项目。网络确保本地回环地址127.0.0.1或localhost可访问。项目源码获取 XXL-JOB 的官方仓库在 GitHub 和 Gitee 上。我们以 Gitee 为例# 克隆调度中心和执行器示例项目 git clone https://gitee.com/xuxueli/xxl-job.git解压后你会看到两个核心目录xxl-job-admin/调度中心项目。xxl-job-executor-samples/执行器示例项目内含 Spring Boot 等多种框架示例。4. 调度中心配置详解与启动调度中心是一个标准的 Spring Boot Web 应用。它的配置核心在application.properties或application.yml和数据库初始化脚本。4.1 初始化数据库在你的 MySQL 中创建一个数据库例如xxl_job。执行项目/doc/db/tables_xxl_job.sql脚本。这个脚本会创建任务、日志、执行器注册信息等所有必要的表。4.2 配置调度中心打开xxl-job-admin/src/main/resources/application.properties文件关注以下关键配置# 数据库连接 (根据你的实际情况修改) spring.datasource.urljdbc:mysql://127.0.0.1:3306/xxl_job?useUnicodetruecharacterEncodingUTF-8autoReconnecttrueserverTimezoneAsia/Shanghai spring.datasource.usernameroot spring.datasource.passwordyour_password spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver # 调度中心通讯TOKEN非必填但建议设置以增强安全性 xxl.job.accessTokendefault_token # 调度中心对外服务的地址 (极为重要) # 执行器将通过这个地址来注册和回调。本地测试通常为内网IP或localhost。 # 如果你计划在其他机器部署执行器这里不能写127.0.0.1要写本机能被其他机器访问的IP。 xxl.job.admin.addresseshttp://127.0.0.1:8080/xxl-job-admin重点解释xxl.job.admin.addresses 这个地址是执行器用来主动连接调度中心的。在本地单机测试时用127.0.0.1或localhost没问题。但在 Docker 或跨服务器部署时你必须将其改为调度中心服务器对外的、可被执行器访问的 IP 或域名。例如http://192.168.1.100:8080/xxl-job-admin。填错会导致执行器无法注册调度中心界面上看不到任何执行器。4.3 启动调度中心在xxl-job-admin目录下使用 Maven 命令启动mvn clean package -DskipTests java -jar target/xxl-job-admin-*.jar或者直接在 IDE 中运行XxlJobAdminApplication主类。启动成功后访问http://localhost:8080/xxl-job-admin。默认登录账号/密码是admin/123456。进入后你就能看到 XXL-JOB 强大的管理界面但目前“执行器管理”和“任务管理”页面还是空的因为执行器还没启动和注册。5. 执行器配置详解与任务开发我们现在来配置一个 Spring Boot 执行器并编写一个简单的任务。5.1 添加依赖在你的 Spring Boot 项目中或使用示例项目xxl-job-executor-sample-springboot添加 XXL-JOB 执行器核心依赖。!-- pom.xml -- dependency groupIdcom.xuxueli/groupId artifactIdxxl-job-core/artifactId version2.4.0/version !-- 请使用与调度中心匹配的版本 -- /dependency5.2 配置执行器在application.properties或application.yml中配置执行器。以下是.properties格式示例# 执行器应用名必须唯一用于调度中心识别和分组 xxl.job.executor.appnamexxl-job-executor-sample # 执行器注册地址默认自动获取优先获取网卡IP。也可手动指定用于调度中心回调触发任务。 # 留空则自动获取 ip:port xxl.job.executor.address # 执行器IP自动获取留空即可 xxl.job.executor.ip # 执行器端口号默认 9999。如果端口被占用会自动1尝试直到找到可用端口。 xxl.job.executor.port9999 # 执行器日志路径用于存储任务调度日志 xxl.job.executor.logpath/data/applogs/xxl-job/jobhandler # 执行器日志保留天数默认30天 xxl.job.executor.logretentiondays30 # 调度中心部署地址列表多个用逗号分隔。必须与调度中心配置的 xxl.job.admin.addresses 对应 xxl.job.admin.addresseshttp://127.0.0.1:8080/xxl-job-admin # 与调度中心通信的AccessToken需和调度中心配置的一致 xxl.job.accessTokendefault_token关键配置解读appname这是执行器的“身份证”。调度中心会根据这个名称来分组管理同一业务集群下的多个实例。所有提供相同业务能力的执行器实例应该使用相同的appname。address和port执行器内嵌了一个 Netty HTTP 服务器监听这个端口用来接收调度中心发来的任务触发指令。address自动生成格式为ip:port。确保这个地址能被调度中心网络访问到这是另一个常见的网络坑点。admin.addresses必须指向你刚才启动的调度中心地址。这是执行器主动注册和上报心跳的地址。5.3 编写任务处理器创建一个 Java 类使用XxlJob注解来定义一个任务。// 文件路径src/main/java/com/example/demo/job/SampleXxlJob.java import com.xxl.job.core.context.XxlJobHelper; import com.xxl.job.core.handler.annotation.XxlJob; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; Component public class SampleXxlJob { private static Logger logger LoggerFactory.getLogger(SampleXxlJob.class); /** * 一个简单的示例任务 * 1. 在调度中心新建任务时JobHandler 属性就填写这个方法名 demoJobHandler * 2. 任务参数可以通过 XxlJobHelper.getJobParam() 获取 */ XxlJob(demoJobHandler) public void demoJobHandler() throws Exception { // 获取调度中心传入的参数 String param XxlJobHelper.getJobParam(); XxlJobHelper.log(XXL-JOB, Hello World! Param: param); // 模拟业务处理 for (int i 0; i 5; i) { XxlJobHelper.log(beat at: i); Thread.sleep(1000); } // 决定任务执行结果 // 默认成功无需返回。若需失败可 // XxlJobHelper.handleFail(任务执行失败原因...); // 或抛出异常 logger.info(SampleXxlJob executed successfully. Param: {}, param); } /** * 另一个任务示例处理耗时任务支持分片广播 */ XxlJob(shardingJobHandler) public void shardingJobHandler() throws Exception { // 获取分片参数当前分片索引 总分片数 int shardIndex XxlJobHelper.getShardIndex(); int shardTotal XxlJobHelper.getShardTotal(); XxlJobHelper.log(分片参数当前分片序号 {}, 总分片数 {}, shardIndex, shardTotal); // 模拟处理分片数据 // 例如有100条数据总分片数为2则索引0的处理0-49索引1的处理50-99 // 实际业务中可根据分片参数去数据库查询自己该处理的那部分数据 // ListData myDataList dataService.findByShard(shardIndex, shardTotal); // process(myDataList); XxlJobHelper.log(分片任务执行完成。); } }5.4 配置执行器 BeanSpring Boot 旧版本可能需要对于较新的 XXL-JOB 版本和 Spring Boot通常通过自动配置即可。如果遇到执行器无法启动可以检查或手动配置XxlJobSpringExecutorBean。// 文件路径src/main/java/com/example/demo/config/XxlJobConfig.java 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; } }5.5 启动执行器启动你的 Spring Boot 应用。观察日志如果看到类似下面的信息说明执行器启动成功并尝试向调度中心注册 xxl-job config init. xxl-job register jobhandler success, name:demoJobHandler, class:com.example.demo.job.SampleXxlJob ... xxl-job executor server start success, nettype class com.xxl.job.core.server.EmbedServer, port 99996. 调度中心界面操作与任务配置现在执行器已经启动并尝试注册。我们回到调度中心管理界面 (http://localhost:8080/xxl-job-admin)。6.1 查看执行器注册情况点击左侧菜单【执行器管理】。你应该能看到一个 AppName 为xxl-job-executor-sample的执行器。如果“注册方式”是“自动注册”下面会列出该执行器注册上来的机器地址如192.168.1.5:9999。如果列表为空请检查执行器配置的xxl.job.admin.addresses是否正确。网络是否互通执行器能否 ping 通调度中心地址。调度中心和执行器的accessToken是否一致如果配置了。查看执行器启动日志是否有注册失败的错误信息。6.2 新建并配置一个任务点击左侧菜单【任务管理】然后点击【新增】。填写任务表单这是核心执行器选择刚才看到的xxl-job-executor-sample。任务描述自定义如“测试示例任务”。路由策略选择“第一个”或“轮询”。决定任务触发时如果该执行器有多个实例发给哪一个。Cron填写 Cron 表达式如0/30 * * * * ?表示每30秒执行一次。运行模式选择 “BEAN”。JobHandler这里必须填写你在代码中XxlJob注解里定义的值即demoJobHandler。任务参数可选可以在这里传入字符串在任务中通过XxlJobHelper.getJobParam()获取。阻塞处理策略选择“单机串行”默认表示如果上一次调度没执行完下一次调度会等待。失败重试次数大于0时任务失败后会自动重试。点击【保存】。6.3 启动与测试任务在任务列表找到刚创建的任务点击操作栏的【启动】。等待 Cron 表达式触发或点击【执行一次】手动触发。点击操作栏的【查看日志】可以实时看到任务执行的日志包括我们在代码中用XxlJobHelper.log打印的信息。如果日志显示“任务触发成功”、“处理结果成功”并且能看到我们打印的 “XXL-JOB, Hello World!” 等信息那么恭喜你一个完整的 XXL-JOB 调度链路已经跑通了7. 常见问题与排查思路90%的坑都在这里在实际部署中你可能会遇到各种问题。下面是一个快速排查清单。问题现象可能原因排查方式解决方案调度中心看不到执行器1. 执行器配置的admin.addresses错误。2. 网络不通。3. 执行器启动失败。1. 检查执行器日志看是否有注册相关的错误。2. 在执行器机器上用curl或浏览器访问调度中心地址看是否通。3. 检查执行器端口默认9999是否被占用。1. 修正admin.addresses为调度中心真实可访问的地址。2. 开放防火墙/安全组端口。3. 更换执行器端口或杀死占用进程。任务触发失败日志显示“任务结果丢失”调度中心无法访问执行器的address:port。1. 在调度中心服务器上telnet或curl执行器的注册地址如192.168.1.5:9999。2. 检查执行器日志看是否收到了触发请求。1. 确保执行器address是调度中心可访问的IP不要是127.0.0.1或localhost。2. 若在 Docker 或 K8s 内需配置正确的网络模式和端口映射。任务状态一直是“运行中”1. 任务执行超时默认30分钟。2. 任务逻辑死循环或长时间阻塞。3. 执行器进程崩溃未返回结果。1. 查看执行器应用日志看任务是否正常结束。2. 检查任务逻辑是否有无限循环或长时间等待如死锁。1. 优化任务逻辑避免超时。2. 在调度中心任务配置中可以设置“任务超时时间”。3. 确保执行器应用健康。XxlJob注解的任务未注册1. Spring 未扫描到 Bean。2. 执行器 Bean (XxlJobSpringExecutor) 未正确初始化。1. 检查任务类是否有Component等注解。2. 检查执行器启动日志是否有register jobhandler success的记录。1. 确保任务类在 Spring 扫描路径下。2. 检查XxlJobConfig配置类是否正确加载。分片任务不生效1. 路由策略未选择“分片广播”。2. 执行器只有一个实例。1. 在调度中心任务配置中“路由策略”选择“分片广播”。2. 启动多个相同appname的执行器实例。1. 正确配置路由策略。2. 分片总数 (shardTotal) 由调度中心动态计算等于当前健康执行器实例数。网络问题终极检查清单执行器 - 调度中心在执行器机器上执行curl http://调度中心IP:端口/xxl-job-admin/actuator/health(或/xxl-job-admin)应能返回正常响应。调度中心 - 执行器在调度中心机器上执行curl http://执行器IP:9999/(9999是执行器端口)应能返回 “xxl-job executor running.”。防火墙/安全组确保双方机器的对应端口调度中心8080执行器9999都已对对方IP开放。8. 最佳实践与工程建议掌握了基础配置后这些进阶实践能让你的 XXL-JOB 用得更稳、更高效。8.1 配置管理AccessToken生产环境务必配置复杂令牌并确保调度中心和执行器配置一致。这是最基本的安全防线。数据库连接池调度中心的application.properties中建议配置合理的数据库连接池参数如HikariCP以应对高频调度。日志清理根据业务量调整logretentiondays避免日志表无限膨胀。XXL-JOB 调度中心有内置的日志清理线程。8.2 任务设计任务幂等性任何任务逻辑都要考虑幂等。因为网络超时可能导致调度中心重试即使你的任务已经执行成功。确保重复执行不会产生副作用。超时设置为长时间任务设置合理的“任务超时时间”避免僵尸任务占用调度线程。失败告警在调度中心配置“任务失败告警”可以邮件或Webhook通知负责人。这是线上运维的必备项。避免耗时操作任务处理器方法应尽快返回。如果需要处理大量数据考虑拆分成多个小任务或使用“分片广播”模式让多个执行器实例并行处理。8.3 高可用与集群部署调度中心集群部署多个调度中心实例并指向同一个数据库。它们通过数据库锁实现集群调度自动实现负载均衡和故障转移。前端用 Nginx 做负载均衡即可。执行器集群部署多个相同appname的执行器实例。调度中心会自动感知。通过“路由策略”如轮询、故障转移来分配任务实现执行器的高可用和水平扩展。数据库高可用为 MySQL 配置主从复制或集群确保调度中心元数据的安全。8.4 监控与运维健康检查调度中心提供了/actuator/health端点Spring Boot Actuator可以集成到公司的监控系统。自定义告警除了内置的邮件告警可以扩展XxlJobCompleter接口实现将任务执行结果推送到自定义监控平台如 Prometheus Grafana。版本一致性确保调度中心和执行器使用的xxl-job-core版本一致避免因协议不兼容导致通信失败。9. 总结XXL-JOB 的配置核心本质上是建立调度中心与执行器之间稳定、双向的网络通信并确保双方对彼此的身份appname,accessToken达成共识。很多初学者遇到的“执行器不显示”、“任务触发失败”问题九成以上都源于网络或地址配置错误。通过本文你应该已经掌握了从零搭建、配置、到编写和运行一个任务的完整流程。更重要的是你理解了每个配置项的意义和它们之间的关联这能帮助你在更复杂的生产环境如 Docker、K8s、跨机房中快速定位和解决问题。下一步你可以探索更多高级特性比如GLUE 模式在调度中心 Web 界面直接编写和运行脚本Shell、Python等适合轻量、临时的任务。父子任务建立任务间的依赖关系实现工作流。调度线程池调优根据任务并发量调整调度中心的线程池大小。建议将你的测试项目保存好作为日后排查问题的参考模板。在分布式系统中一个可靠的任务调度平台是业务稳定性的基石而扎实的配置是这一切的开始。