一、前置基础:GLUE模式 核心定义 + 本质
1.1 GLUE 全称 & 核心定位
GLUE 是 Generate Logic Use Expression 的缩写,直译「使用表达式生成逻辑」。
XXL-JOB 中的 GLUE模式(脚本式),是和 Bean模式(注解式) 并列的两大核心任务模式,核心特征:
✅ 任务的业务逻辑代码,直接在【调度中心XXL-JOB Admin】的Web页面编写/保存/修改
✅ 脚本代码存储在调度中心的数据库中,完全不侵入业务项目(执行器)
✅ 无需在业务项目写任何任务代码、无需打包、无需重启项目,修改脚本后立即生效
✅ 主流用「GLUE(Java)」,也支持 GLUE(Shell)、GLUE(Python)、GLUE(NodeJS) 等脚本类型
1.2 核心结论
GLUE模式 底层核心原理:「调度中心存储脚本 + 执行器动态拉取 + 运行时动态编译/解析 + 类加载反射执行」
对比Bean模式核心区别:Bean模式是「业务项目写死代码 → 编译打包 → 执行器启动加载」;GLUE模式是「Admin写脚本 → 不编译打包 → 执行器运行时动态处理执行」
一句话总结:Bean模式是「静态预编译」,GLUE模式是「动态运行时编译/解析」
二、GLUE(Java) 底层实现原理(99%的GLUE使用场景)
你在Admin后台写的GLUE(Java)脚本,不是「解释执行」的伪代码,而是标准的Java源代码,XXL-JOB对它的执行逻辑,是所有GLUE模式里最复杂、也是最核心的,底层分「5大核心步骤」,环环相扣,这也是GLUE模式的灵魂:
✅ 核心前提:GLUE(Java) 脚本的强制规范
在Admin后台写的Java脚本,必须遵守一个固定规范,这是能被执行的基础,没有例外:
java
public class JobHandler implements com.xxl.job.core.handler.IJobHandler {
@Override
public void execute() throws Exception {
// 你的业务逻辑,比如查询数据库、调用接口、打印日志等
System.out.println("GLUE模式Java脚本执行成功");
}
}
为什么要遵守这个规范?
因为XXL-JOB的执行器,只认识实现了IJobHandler接口的任务处理器 ,Bean模式的@XxlJob注解方法,底层也是被封装成了该接口的实现类,这是XXL-JOB所有任务的「统一执行标准」。
✅ 核心步骤(完整底层链路,从写脚本到执行完成)
步骤1:脚本代码「持久化存储」- 存在调度中心,而非执行器
你在Admin后台写完GLUE(Java)脚本,点击「保存」的那一刻:
- 脚本的完整Java源码字符串 ,会被存入调度中心的数据库表
xxl_job_info中; - 对应的字段:
glue_source存储「源码字符串」、glue_type标记「GLUE(Java)」、glue_updatetime存储「脚本更新时间戳」; - 脚本代码不会同步到任何执行器节点,执行器此时完全不知道脚本内容,也不会加载任何脚本相关的类。
步骤2:调度触发时,执行器「主动拉取最新脚本源码」
当调度中心按CRON规则触发任务,给执行器发送调度请求时,请求中只带「任务ID+脚本更新时间戳」,不带源码:
- 执行器接收到调度请求后,会拿着「任务ID」去调度中心的Admin接口发起请求,拉取该任务对应的「最新GLUE(Java)源码」;
- 执行器内部有「源码缓存机制」:如果本次拉取的脚本更新时间戳,和本地缓存的一致,就不会重复拉取,直接用缓存的源码,提升性能;如果不一致(脚本被修改过),就拉取最新源码,覆盖本地缓存。
步骤3:Java源码「内存级动态编译」- 无class文件落地磁盘
执行器拿到Java源码字符串后,会触发 「动态编译」 流程,这是GLUE(Java)最核心的一步:
- XXL-JOB 直接复用 JDK原生的Java编译器 (
javax.tools.JavaCompiler),这是JDK8及以上自带的能力,无需引入任何第三方编译依赖; - 编译器将「Java源码字符串」编译成 Java字节码(byte[]) ,这个过程是纯内存操作 ,不会在执行器服务器生成任何
.java或.class文件落地磁盘; - 编译后的字节码,是GLUE脚本能被执行的「中间产物」,也是连接源码和执行的桥梁。
步骤4:自定义类加载器「加载字节码」- 核心:隔离+热更+防冲突
编译出字节码后,执行器会用 XXL-JOB内置的「自定义类加载器」 加载这个字节码,生成Java的Class对象,这一步是GLUE模式的「精髓设计」,也是解决很多问题的关键:
✔️ 为什么不用JVM的系统类加载器/应用类加载器?
如果用系统类加载器加载,会有3个致命问题:
- 类冲突 :不同GLUE任务的脚本,可能写了同名的
JobHandler类,系统类加载器加载后会冲突; - 无法热更新:脚本修改后,重新编译的字节码,系统类加载器无法重复加载同名类(JVM的类加载机制:同一个类加载器,全类名相同的类只能加载一次);
- 资源污染:GLUE脚本的类,会混入业务项目的类加载器中,可能影响业务代码的运行。
✔️ 自定义类加载器的核心优势
XXL-JOB的自定义类加载器,是「独立的、临时的、任务隔离的」:
- 每个GLUE任务的脚本,都会被专属的类加载器加载,不同任务之间完全隔离,无类冲突;
- 脚本修改后,重新编译的字节码,会被新的类加载器加载,完美实现「热更新」,无需重启执行器;
- 类加载完成后,执行完毕,类加载器会被回收,不会污染执行器的核心类加载器,无内存泄漏风险。
步骤5:反射实例化 + 统一执行 - 最终触发业务逻辑
- 类加载完成后,执行器通过 Java反射机制,实例化该Class对象(创建JobHandler实例);
- 执行器的任务线程池,调用该实例的
execute()方法,执行你写的业务逻辑; - 执行完成后,执行器将「执行结果(成功/失败)+ 执行日志」上报给调度中心,完成整个GLUE任务的执行。
三、其他GLUE模式 底层实现原理(Shell/Python/NodeJS,简单易懂)
对于GLUE(Shell)、GLUE(Python)、GLUE(NodeJS)这类「脚本语言」,底层原理和GLUE(Java)完全不同,没有编译过程,只有「解析执行」,逻辑非常简单,也是XXL-JOB的轻量实现:
✅ 核心原理:Java 调用「系统本地命令行」执行脚本
- 脚本源码同样是在Admin后台编写,保存后存入数据库的
glue_source字段; - 调度触发后,执行器拉取到「脚本源码字符串」;
- XXL-JOB会在执行器的服务器上,自动生成一个临时的脚本文件 (比如
.sh/.py文件),将源码写入该文件; - 通过Java的
Runtime.exec()/ProcessBuilderAPI,调用系统的「命令行工具」执行该脚本(比如sh xxx.sh、python xxx.py); - 执行完成后,读取脚本的执行日志和返回码,上报给调度中心,同时删除临时脚本文件,不留痕迹;
✅ 核心特点
- 无需编译,直接调用系统命令,逻辑简单,性能一般;
- 强依赖执行器服务器的「运行环境」:执行GLUE(Python)必须装Python环境,执行GLUE(Shell)必须是Linux服务器;
- 安全性较低:脚本可以执行任意系统命令,存在一定的服务器安全风险。
四、GLUE模式 VS Bean模式 底层核心差异
这也是为什么GLUE模式「极少用」,Bean模式「99%的场景都用」的核心原因,所有差异都源于「静态预编译」和「动态运行时编译」的底层区别,建议对比记忆:
| 对比维度 | GLUE模式(Java) | Bean模式(注解式) |
|---|---|---|
| 代码编写位置 | 调度中心Admin后台Web页面 | 业务项目(执行器)的Java代码中 |
| 代码存储位置 | 调度中心数据库 xxl_job_info.glue_source |
执行器的class文件中(打包在jar包) |
| 编译时机 | 任务执行时「运行时动态编译」(内存级) | 项目打包时「静态预编译」(本地编译) |
| 类加载方式 | XXL-JOB自定义类加载器(隔离/热更) | Spring的应用类加载器(全局加载) |
| 执行方式 | 反射实例化 → 调用execute方法 | Spring容器管理Bean → 反射调用注解方法 |
| Spring资源调用 | ❌ 无法直接@Autowired注入Spring Bean | ✅ 无缝注入所有Spring Bean(Service/Mapper) |
| 依赖支持 | ❌ 只能用JDK原生API,无法调用业务依赖 | ✅ 支持所有业务依赖、第三方SDK、数据库连接池等 |
| 热更新能力 | ✅ 完美支持,改脚本保存后立即生效 | ❌ 不支持,改代码必须打包重启执行器 |
| 执行性能 | 稍差(每次执行有编译/加载的微小开销) | 极高(类加载一次,永久复用,无额外开销) |
| 代码规范/版本控制 | ❌ 无版本控制,代码零散,无法团队协作 | ✅ 遵循项目规范,Git版本控制,团队协作友好 |
五、GLUE模式 2个核心痛点(为什么极少用?根源在这里)
GLUE模式(脚本式,极少用),不是它的设计不好,而是它的痛点刚好击中了企业开发的核心诉求,这也是为什么实际开发中几乎不用的原因,痛点全部源于底层原理的限制,无法规避:
❌ 痛点1:无法调用业务项目的任何资源(核心致命问题)
GLUE(Java)的脚本,是被「独立的自定义类加载器」加载的,这个类加载器不在Spring容器的管辖范围内,也无法访问到业务项目的类加载器中的任何类:
- 无法用
@Autowired注入Service、Mapper、RedisTemplate、数据库连接池; - 无法调用业务项目的自定义工具类、第三方SDK(比如OSS、短信);
- 只能用JDK原生的API(比如System.out、String、ArrayList),能干的事情非常有限。
这是GLUE模式最大的痛点!一个定时任务,99%的场景都需要操作业务数据、调用业务逻辑,而GLUE模式做不到,这也是它「极少用」的核心原因。
GLUE (Java) 的脚本,是被谁加载的?
GLUE (Java) 虽然叫「Java」,但它的本质是 Groovy 脚本(XXL-JOB 的 GLUE 所有模式,底层都是 Groovy),它的运行流程是:
- 你在管理台写的 Java 代码,本质是Groovy 语法的 Java 代码片段;
- 任务触发时,XXL-JOB 执行器会创建一个 「独立的、全新的、专属的 」GroovyClassLoader 类加载器;
- 这个GroovyClassLoader会动态编译你写的 GLUE 脚本,然后动态加载编译后的 class 文件;
- 最后由这个GroovyClassLoader 创建脚本的实例对象,执行
execute()方法。
JVM 的核心铁律(类加载器的沙箱隔离机制)
这是 Java 虚拟机的底层安全机制 ,是无法绕过、无法破解的硬性规则,记住这句话:
✅ 没有继承关系的两个类加载器,在 JVM 中是相互隔离的「沙箱」,彼此之间完全不可见、不可访问!
✅ 如果A、B没有继承关系,那么A 类加载器加载的类,*绝对不能直接访问 / 实例化 / 调用 ** B 类加载器加载的任何类,哪怕这个类的全类名一模一样(比如com.xxx.utils.StringUtil);
✅ 类加载器的隔离是「双向隔离」:业务的 AppClassLoader 加载的类,访问不到 GroovyClassLoader 的类;GroovyClassLoader 加载的 GLUE 脚本,也访问不到 AppClassLoader 的业务类。
为什么 GLUE 脚本能调用 JDK 的类(String/ArrayList/HashMap)?
你肯定发现了,GLUE 里写new ArrayList<>()、String.valueOf()这些 JDK 的类是完全没问题的,这是因为:
- JDK 的核心类(
java.lang.*、java.util.*等),是被 JVM 的启动类加载器(BootstrapClassLoader) 加载的,这个加载器是所有自定义类加载器的「父加载器」。 - 根据 Java 的「双亲委派机制 」:所有子加载器都可以无条件访问父加载器加载的类。
- 所以 GLUE 的 GroovyClassLoader 能访问到 JDK 的类,但绝对访问不到平级的 AppClassLoader 加载的业务类 / SDK 类。
❌ 痛点2:代码无规范、无版本控制,运维风险高
- 脚本代码写在Admin后台,无法纳入Git版本控制,代码修改无记录、无回滚能力,一旦改错,很难追溯;
- 脚本代码零散在Admin中,无法和业务代码联动,团队协作困难;
- GLUE(Shell/Python)还依赖执行器的运行环境,环境不一致就会执行失败,运维成本高。
六、GLUE模式的 适用场景
虽然极少用,但GLUE模式也有它的「专属价值」,它的所有优点,都是为了「快速解决简单问题 」,这也是XXL-JOB保留这个功能的原因,唯一适用的2个场景:
✅ 场景1:简单的、无业务依赖的轻量任务
比如:定时打印日志、定时调用一个第三方公开接口、定时清理服务器临时文件、定时发送一个测试短信等,不需要调用业务资源,只用JDK原生API就能完成的任务。
✅ 场景2:需要「紧急热修复」的任务
比如:线上有一个Bean模式的任务出了BUG,需要紧急修改逻辑,但业务项目打包重启需要10分钟,而线上业务不允许停这么久,此时可以:
- 临时把任务改成GLUE模式;
- 在Admin后台写修复后的脚本,立即生效;
- 等业务低峰期,再把代码改回Bean模式,打包重启执行器。
这是GLUE模式最实用的「应急功能」,也是它的核心价值所在。
七、总结
✅ 1. GLUE(Java) 核心原理
Admin存储Java源码 → 执行器拉取源码 → JDK动态编译为字节码 → 自定义类加载器加载 → 反射实例化 → 执行execute方法,本质是「动态编译+动态加载+反射执行」。
✅ 2. GLUE(Shell/Python) 核心原理
Admin存储脚本源码 → 执行器拉取源码 → 生成临时脚本文件 → Java调用系统命令行执行 → 回收临时文件,本质是「Java调用系统命令」。
✅ 3. GLUE模式的核心优势
无需打包、无需重启、完美热更新,这是Bean模式永远无法做到的。
✅ 4. GLUE模式的核心劣势
无法调用业务资源、无版本控制、性能稍差,这是它极少用的根源。
✅ 5. 核心定位
GLUE模式 是 XXL-JOB的「补充功能」,不是「主流功能」,它的存在是为了弥补Bean模式「热更新困难」的短板,而Bean模式是为了解决「业务开发核心诉求」的主流方案,两者相辅相成,而非互斥。