JMeter vars.put 操作详细指南
1. 概述
vars 是 JMeter 内置的线程级变量操作对象,用于在当前线程的不同元件间传递数据(如 PreProcessor → Sampler → PostProcessor)。vars.put() 是其核心方法之一,用于将数据存储为线程级变量。
**tags: [作用域]**:
vars仅对当前线程可见,不同线程的vars是完全独立的(线程隔离)。
2. vars.put() 基本用法
2.1 语法
// 语法:vars.put(变量名, 变量值);
// 说明:变量值必须为字符串类型(非字符串类型需先转换为字符串)
vars.put("key", "value");
2.2 示例:存储不同类型的数据
示例 1:存储字符串
// 存储字符串变量
vars.put("username", "testuser");
vars.put("password", "testpass");
// 验证存储结果
log.info("用户名:" + vars.get("username")); // 输出:用户名:testuser
示例 2:存储数值
**tags: [类型转换]**:
vars.put()仅支持字符串,存储数值时需先转换为字符串。
// 方法 1:使用 toString() 转换
int age = 25;
vars.put("userAge", age.toString());
// 方法 2:使用字符串拼接转换
int score = 95;
vars.put("userScore", "" + score);
// 方法 3:使用 String.valueOf() 转换
long timestamp = System.currentTimeMillis();
vars.put("timestamp", String.valueOf(timestamp));
示例 3:存储布尔值
boolean isActive = true;
vars.put("isUserActive", String.valueOf(isActive)); // 存储为 "true"
3. vars 相关方法
3.1 存储对象:vars.putObject()
当需要存储非字符串类型的数据(如数组、列表、Map 等)时,使用 vars.putObject()。
// 语法:vars.putObject(变量名, 对象);
vars.putObject("key", object);
示例:存储数组和 Map
// 存储字符串数组
def ipArray = ["192.168.1.1", "192.168.1.2", "192.168.1.3"];
vars.putObject("ipList", ipArray);
// 存储 Map 对象
def userInfo = ["id": 1, "name": "testuser", "age": 25];
vars.putObject("userMap", userInfo);
// 验证存储结果
log.info("IP 列表长度:" + vars.getObject("ipList").size()); // 输出:3
3.2 获取变量:vars.get()
用于获取之前存储的字符串变量,若变量不存在返回 null。
// 语法:vars.get(变量名);
String value = vars.get("key");
示例
// 获取之前存储的变量
def username = vars.get("username");
def age = vars.get("userAge");
// 使用获取的值
if (username != null) {
log.info("用户:" + username + ",年龄:" + age);
}
3.3 获取对象:vars.getObject()
用于获取之前存储的对象,需进行类型强转。
// 语法:vars.getObject(变量名);
Object value = vars.getObject("key");
示例
// 获取数组对象
def ipList = (List<String>) vars.getObject("ipList");
log.info("第一个 IP:" + ipList[0]); // 输出:192.168.1.1
// 获取 Map 对象
def userMap = (Map<String, Object>) vars.getObject("userMap");
log.info("用户名:" + userMap.get("name")); // 输出:testuser
3.4 移除变量:vars.remove()
从当前线程的变量空间中移除指定变量。
// 语法:vars.remove(变量名);
vars.remove("key");
示例
// 移除变量
vars.remove("username");
// 验证是否移除成功
log.info("用户名是否存在:" + (vars.get("username") == null)); // 输出:true
3.5 清空所有变量:vars.clear()
清空当前线程的所有变量(谨慎使用,可能影响后续元件)。
// 语法:vars.clear();
vars.clear();
示例
// 清空所有变量
vars.clear();
// 验证变量数量
log.info("变量数量:" + vars.entrySet().size()); // 输出:0
4. 常见使用场景
场景 1:PreProcessor 中生成数据传递给 Sampler
**tags: [典型应用]**:在请求前生成动态数据(如唯一 ID、时间戳),并在 Sampler 中使用。
示例:生成唯一请求 ID 并在 HTTP Request 中使用
- 添加 JSR223 PreProcessor(HTTP Request 的子元件):
// 生成唯一请求 ID
def requestId = "REQ_" + System.currentTimeMillis();
vars.put("requestId", requestId);
// 生成时间戳
def timestamp = String.valueOf(System.currentTimeMillis());
vars.put("timestamp", timestamp);
- 在 HTTP Request 中引用:
- Path 字段填写:
/api/test?requestId=${requestId}×tamp=${timestamp} - 实际请求路径会被替换为:
/api/test?requestId=REQ_1678901234567×tamp=1678901234567
- Path 字段填写:
场景 2:PostProcessor 中提取响应数据传递给后续 Sampler
**tags: [数据流转]**:从响应中提取数据(如 token、用户 ID),供后续请求使用。
示例:提取响应中的 token 并在后续请求的 Header 中使用
- 添加 JSR223 PostProcessor(第一个 HTTP Request 的子元件):
// 获取响应体
String response = prev.getResponseDataAsString();
// 正则提取 token
def tokenMatcher = response =~ /"token":"([^"]+)"/;
if (tokenMatcher.find()) {
String token = tokenMatcher.group(1);
vars.put("authToken", token);
log.info("已提取 token:" + token);
}
- 在后续 HTTP Request 的 Header 中引用:
- 添加 Header:
Authorization→ 值填写:Bearer ${authToken}
- 添加 Header:
场景 3:存储复杂数据结构
**tags: [数据结构]**:对于数组、列表等复杂数据,使用
vars.putObject()存储更高效。
示例:存储用户列表并在后续元件中遍历使用
- 在 PreProcessor 中存储用户列表:
// 定义用户列表
def users = [
["id": 1, "name": "user1", "age": 20],
["id": 2, "name": "user2", "age": 25],
["id": 3, "name": "user3", "age": 30]
];
// 存储为对象
vars.putObject("userList", users);
- 在后续 PostProcessor 中使用:
// 获取用户列表
List<Map<String, Object>> userList = (List<Map<String, Object>>) vars.getObject("userList");
// 遍历用户列表
for (int i = 0; i < userList.size(); i++) {
Map<String, Object> user = userList.get(i);
log.info("用户 " + (i+1) + ":" + user.get("name") + ",年龄:" + user.get("age"));
}
5. 注意事项
**tags: [警告]**:以下事项需特别注意,避免使用错误。
5.1 字符串必须加引号
存储字符串时,必须用引号包围(双引号或单引号),否则 Groovy 会将其视为变量名(未定义会报错)。
// 错误:test 被视为变量名(未定义会抛出异常)
// vars.put("var", test); // 抛出 MissingPropertyException
// 正确:用引号包围字符串
vars.put("var", "test");
5.2 跨线程共享需使用 props
vars 仅对当前线程可见,若需跨线程共享数据,应使用 props(全局属性)。
// 存储为全局属性(所有线程可见)
props.put("globalVar", "value");
// 在其他线程中获取
String value = props.get("globalVar");
5.3 变量替换仅在支持的字段中生效
${变量名} 语法仅在 JMeter 支持变量替换的字段中生效(如 HTTP Request 的路径、参数值、Header 等)。
5.4 性能考虑
- 避免在高频执行的元件(如循环中的 Sampler)中频繁调用
vars.put()/vars.get(),可能影响性能。 - 对于复杂数据结构,优先使用
vars.putObject()存储,减少类型转换开销。
6. 与其他变量操作对象的对比
| 操作对象 | 作用域 | 生命周期 | 适用场景 |
|---|---|---|---|
vars |
当前线程 | 线程执行期间 | 线程内数据传递 |
props |
全局(所有线程) | 测试计划执行期间 | 跨线程数据共享 |
ctx |
当前线程 | 线程执行期间 | 访问 JMeter 上下文(如采样器结果) |
prev |
当前线程 | 当前采样器执行后 | 访问上一个采样器的结果 |
7. 完整示例:IP 轮询场景
7.1 需求
定义 IP 列表 ["192.168.1.1", "192.168.1.2", "192.168.1.3"],并在每次请求时按顺序轮询使用。
7.2 实现步骤
- 添加 JSR223 PreProcessor(线程组级别):
// 初始化 IP 列表(仅首次执行时初始化)
if (!vars.containsKey("ipListInitialized")) {
def ipList = ["192.168.1.1", "192.168.1.2", "192.168.1.3"];
vars.putObject("ipList", ipList);
vars.put("ipIndex", "0");
vars.put("ipListInitialized", "true");
log.info("IP 列表已初始化:" + ipList);
}
// 轮询逻辑
def ipList = vars.getObject("ipList");
int index = Integer.parseInt(vars.get("ipIndex"));
int size = ipList.size();
// 获取当前 IP
String currentIp = ipList[index % size];
vars.put("currentIp", currentIp);
// 更新索引
vars.put("ipIndex", String.valueOf((index + 1) % size));
log.info("当前轮询 IP:" + currentIp);
- 在 HTTP Request 中引用:
- Server Name or IP 字段填写:
${currentIp}
- Server Name or IP 字段填写:
7.3 执行结果
- 第 1 次请求:使用 IP
192.168.1.1 - 第 2 次请求:使用 IP
192.168.1.2 - 第 3 次请求:使用 IP
192.168.1.3 - 第 4 次请求:循环使用 IP
192.168.1.1
8. 总结
vars.put() 是 JMeter 中管理线程级变量的核心方法,通过本文的指南,您应已掌握:
- ✅
vars.put()的基本用法和类型转换 - ✅
vars相关方法(如putObject()、get()、remove())的使用 - ✅ 常见使用场景(如数据传递、响应提取、复杂数据存储)
- ✅ 注意事项和性能优化建议
合理使用 vars 对象,可大幅提升 JMeter 脚本的灵活性和可维护性,实现更复杂的测试场景。