第八章. JSR223 与 Groovy:JMeter 的核武器
第八章. JSR223 与 Groovy:JMeter 的核武器
Prorise第八章. JSR223 与 Groovy:JMeter 的核武器
摘要:在前面的章节中,我们通过鼠标点选 GUI 组件完成了大部分任务。但真实业务往往比这复杂得多:比如接口需要 “MD5 加密签名”、需要 “AES 解密响应”、或者需要把数据 “写入本地 Excel”。面对这些需求,GUI 界面束手无策。本章我们将解锁 JMeter 的 JSR223 组件配合 Groovy 语言,让你拥有直接编写代码操控压测逻辑的能力。
本章学习路径
我们将从面板认知开始,一步步掌握脚本编程:
- 8.1 认识 JSR223 组件
- 8.1.1 JSR223 是什么?为什么不是 BeanShell?
- 8.1.2 面板功能区详解(入口与配置)
- 8.2 Groovy 语言速成(面向 Java 开发者)
- 8.2.1 为什么它是 JMeter 的御用语言
- 8.2.2 核心语法差异:丢掉分号与类型
- 8.3 JMeter 的四大内置对象
- 8.3.1
log:你的调试眼睛 - 8.3.2
vars:变量的搬运工 - 8.3.3
props与ctx:跨线程与上下文(了解)
- 8.3.1
- 8.4 实战:手写 MD5 加密前置处理器
- 8.4.1 引入 Java 工具类
- 8.4.2 编写并调试加密脚本
- 8.5 实战:自定义数据写入后置处理器
- 8.5.1 文件流操作
- 8.5.2 将订单号落盘保存
8.1. 认识 JSR223 组件
在 “添加” 菜单中,你会发现很多带有 “脚本” 字样的组件,最著名的就是 BeanShell 和 JSR223。请记住一句话:在 2025 年,请彻底遗忘 BeanShell,只用 JSR223 + Groovy。
8.1.1. 核心概念:Interface vs Language
- JSR223:这是一个 Java 规范(Java Specification Request 223),它定义了一个标准接口,允许 Java 程序调用各种脚本语言(如 Python, Ruby, Groovy)。在 JMeter 中,它是一个 容器。
- Groovy:这才是我们要写的 语言。它完全兼容 Java 语法,但更简洁。
- 为什么要用它?
- BeanShell 是解释执行的,性能极差(并发一高就会卡死)。
- Groovy 支持 “编译缓存”,JMeter 会把它编译成原生的
.class字节码运行,性能几乎等同于原生 Java。
8.1.2. 面板功能区详解
让我们先找到并打开这个组件。
操作步骤:
- 右键点击 线程组 -> 添加 -> 取样器 (Sampler) -> JSR223 取样器。
- 你会看到如下界面,我们需要关注三个核心区域:
关键配置项说明:
- Language (语言):
- 必须选择
groovy。千万不要选java或beanshell,否则无法享受性能优化。
- 必须选择
- Cache compiled script if available (缓存编译脚本):
- 必须勾选。这是性能起飞的关键。勾选后,这段代码只会被编译一次,之后 100 万次循环都直接运行机器码。
- Script (脚本编辑区):
- 这里就是我们写代码的地方。虽然它像个记事本,没有代码提示,但它支持标准的 Java/Groovy 语法。
8.2. Groovy 语言速成
对于已经掌握 Spring Boot 的你来说,学习 Groovy 是 “零成本” 的。因为 任何合法的 Java 代码都是合法的 Groovy 代码。
你可以直接在脚本区写 System.out.println("Hello");,它是能跑的。但 Groovy 提供了一些 “语法糖”,让代码更简洁。
8.2.1. 核心语法差异表
| 特性 | Java 写法 | Groovy 写法 (推荐) | 优势 |
|---|---|---|---|
| 分号 | String name = "Jack"; | String name = "Jack" | 可以省略分号,代码更干净。 |
| 类型定义 | String id = "123"; | def id = "123" | 使用 def 自动推断类型,类似 JS 的 let。 |
| 字符串插值 | "ID is " + id | "ID is ${id}" | 使用双引号 + ${} 直接拼接变量。 |
| Get/Set | user.getName() | user.name | 自动调用 getter/setter 方法。 |
建议:作为初学者,为了避免出错,你完全可以 直接写标准的 Java 代码。等你熟练了,再尝试 Groovy 的简化写法。
8.3. JMeter 的四大内置对象
在 Script 编辑区写代码时,JMeter 已经默默地往这一小块空间里注入了几个 “上帝对象”。你不需要 new,直接就能用。
8.3.1. log:你的调试眼睛
在 GUI 界面写代码没有断点调试,我们只能靠打印日志来观察变量。
- 代码:
1
2log.info("这是普通信息");
log.error("这是报错信息"); - 查看位置:点击 JMeter 界面右上角的 黄色感叹号图标,底部会弹出一个控制台窗口,你的日志就显示在那里。
8.3.2. vars:变量的搬运工(最重要)
vars 是 JMeterVariables 类的实例。它连接了 GUI 组件 和 代码世界。
读取变量(从 GUI -> 代码):假设你在 “用户定义的变量” 中定义了
target_host。1
String ip = vars.get("target_host"); // 获取变量值
写入/修改变量(从 代码 -> GUI):假设你想把计算好的结果传给下一个 HTTP 请求。
1
vars.put("new_token", "xwq89-sdsd-223"); // 创建名为 new_token 的变量
8.4. 实战 A:前置处理器 - 攻克 MD5 签名校验
在真实的企业级开发中,为了防止请求被篡改,后端往往要求前端对核心参数进行加密签名。例如:注册接口要求密码必须传输 32 位 MD5 密文,如果传输明文直接报错。
JMeter 的 GUI 组件没有自带 MD5 加密功能,这时候就轮到 JSR223 前置处理器大显身手了。
8.4.1. 第一步:改造靶场(制造困难)
为了模拟这个场景,我们需要先在 Spring Boot 项目中增加一个“强制校验 MD5”的注册接口。
文件路径:src/main/java/com/demo/jmeterdemo/controller/AuthController.java
请在 AuthController 类中追加以下代码:
1 | /** |
操作提醒:
- 粘贴代码后,请重启 Spring Boot 项目。
- 确保控制台无报错,端口 8080 正常监听。
8.4.2. 第二步:遭遇失败(复现问题)
我们先尝试用常规方式去请求,看看会发生什么。
- 在 JMeter 线程组下新建一个 HTTP 请求,命名为 " API_注册 "。
- Method:
POST - Path:
/api/auth/register - Body Data:
1
2
3
4{
"username": "admin",
"password": "123456"
} - 运行测试,查看 察看结果树。
- 响应结果:
{"code":400, "msg":"Security Error: Password must be MD5 encrypted!"} - 分析:后端校验生效,传输明文 “123456” 被拒绝。我们需要在发送请求 之前,把 “123456” 变成 MD5 密文。
- 响应结果:
8.4.3. 第三步:脚本编程(JSR223 救场)
我们需要使用 前置处理器 (PreProcessor),它的执行时机是在 HTTP 请求发送 之前。
操作流程:
修改 Body:将明文密码替换为变量占位符。
1
2
3
4{
"username": "admin",
"password": "${md5_pwd}"
}(注:变量
${md5_pwd}目前还不存在,我们马上用代码生成它)添加组件:右键点击 " API_注册_成功 " -> 添加 -> 前置处理器 -> JSR223 预处理程序。
配置面板:
- 语言:选择
groovy(必须!)。 - 缓存:勾选
Cache compiled script if available。
- 语言:选择
编写 Groovy 脚本:
请在 Script 编辑区输入以下代码。这段代码利用了 JMeter 自带的 commons-codec 库,这是 Java 处理加密的标准姿势。
1 | // 1. 导入加密工具类 (JMeter 自带,无需下载 jar 包) |
8.4.4. 第四步:全链路验证(闭环检查)
脚本写好了,能不能跑通?我们需要检查三个地方。
操作步骤:
- 打开日志监视器:点击 JMeter 右上角的黄色感叹号图标(或菜单栏 选项 -> 日志查看器),清空旧日志。
- 运行脚本:点击启动按钮。
- 检查点 1:看日志
- 观察下方控制台,是否输出了
加密结果: e10adc3949ba59abbe56e057f20f883e? - 如果有,说明 Groovy 代码运行正常,加密逻辑成功。
- 观察下方控制台,是否输出了
- 检查点 2:看请求体 (Request Body)
- 在 察看结果树 中选中 " API_注册_成功 "。
- 点击 请求 (Request) 选项卡 -> Request Body。
- 观察
password字段:"password": "e10adc3949ba59abbe56e057f20f883e"。 - 说明
vars.put生效了,变量成功替换了占位符。
- 检查点 3:看响应 (Response)
- 点击 响应数据 (Response Data)。
- 看到
{"code":200, "msg":"Register Success"}。 - 说明后端校验通过。
通过这四步,我们完整实现了一个 “Java 加密 -> JMeter 变量 -> HTTP 请求” 的数据流转。
8.5. 实战 B:后置处理器 - 核心数据落盘保存
在压测过程中,我们经常需要把生产出来的数据(比如:注册成功的用户名、下单成功的订单号)保存下来,作为下一轮压测的输入数据,或者发给其他部门进行对账。
JMeter 的 “保存响应到文件” 组件功能很弱(只能存整个响应),要想灵活地只存一个 ID,必须使用 JSR223 后置处理器。
8.5.1. 第一步:确认数据源
我们要保存的是 下单接口 返回的 orderId。
- 确保你已经有了 " API_下单 " 接口(参考第 5 章)。
- 确保该接口下挂载了 JSON 提取器。
- 变量名称:
orderId - JSON 路径:
$.orderId
- 变量名称:
8.5.2. 第二步:编写落盘脚本
我们需要在提取出 orderId 之后,把它写入电脑的硬盘里。
操作步骤:
- 右键点击 " API_下单 " -> 添加 -> 后置处理器 -> JSR223 后置处理程序。
- 注意顺序:它必须放在 “JSON 提取器” 的 下方(因为要先提取,再写入)。
- 配置面板:语言选
groovy,勾选缓存。
编写 Groovy 脚本:
1 | // 1. 从 JMeter 变量池获取 OrderID |
8.5.3. 第三步:验证数据落盘
代码写得再漂亮,文件里有数据才是硬道理。
验证流程:
- 清理环境:如果
D:/jmeter_orders.csv已经存在,建议先手动删除它,确保我们看到的是新的。 - 运行脚本:设置线程组循环 5 次,点击启动。
- 观察 JMeter:
- 查看日志窗口,应该有 5 条
成功保存订单ID: xxxx的记录。 - 确保没有红色的
写入文件失败报错。
- 查看日志窗口,应该有 5 条
- 检查硬盘文件:
- 打开
D:/盘(或你设置的路径)。 - 找到
jmeter_orders.csv,用记事本打开。 - 预期结果:应该看到 5 行不同的数字 ID。
- 打开
1 | 1731988888123 |
如果能看到这个文件,恭喜你,你已经掌握了用 JMeter 处理复杂数据流的核心技能。
8.6. 本章小结
本章我们跨越了 GUI 的边界,进入了代码的领域。这是从中级测试工程师迈向高级的关键一步。
核心要点:
- 工具链:坚决使用 JSR223 + Groovy,配合 Cache 选项,性能是 BeanShell 的百倍。
- 调试法:脚本是看不见摸不着的,必须依赖
log.info()打印关键变量,通过日志控制台来 “透视” 运行过程。 - 数据流:
- GUI -> 代码:
vars.get("key") - 代码 -> GUI:
vars.put("key", "value")
- GUI -> 代码:
- 安全性:在进行文件读写等高危操作时,务必进行 判空校验 (null check) 和 异常捕获 (try-catch),防止因为一条脏数据导致整个测试中断。








