Java 21+Maven环境下JMeter测试日志保存及XStream报错解决
JDK 21环境下JMeter测试执行日志获取方案
报错原因说明
你遇到的错误确实是JDK 21的模块系统(JPMS)限制导致:XStream(JMetersaveTree()方法依赖的序列化库)需要反射访问java.util包的内部成员,但JDK 21默认不允许未命名模块访问这些受限包,因此序列化操作失败。
下面提供三种无需注释saveTree()或能替代获取测试详情的方案:
方案1:直接配置JMeter结果收集器输出日志文件
不用依赖saveTree(),直接通过ResultCollector组件生成标准JMeter结果文件(CSV/XML格式),步骤如下:
在你的测试代码中添加结果收集器:
import org.apache.jmeter.reporters.ResultCollector; import org.apache.jmeter.reporters.Summariser; import org.apache.jmeter.save.SaveService; import org.apache.jorphan.collections.HashTree; // 初始化JMeter配置、创建测试计划HashTree(保留你已有代码) HashTree testPlanTree = ...; // 添加CSV结果收集器 ResultCollector resultCollector = new ResultCollector(new Summariser()); resultCollector.setFilename("jmeter-test-results.csv"); // 指定输出文件路径 // 如果要XML格式,替换为以下两行: // resultCollector.setFilename("jmeter-test-results.xml"); // resultCollector.setSaveConfig(SaveService.getXmlSaveConfig()); // 将结果收集器添加到测试树 testPlanTree.add(testPlanTree.getArray()[0], resultCollector); // 执行测试(保留你已有代码)
测试完成后,直接打开生成的CSV/XML文件即可查看请求响应时间、状态码、响应大小等所有测试详情。
方案2:添加JVM参数开放模块权限,恢复saveTree()功能
如果必须保留saveTree(),可以在启动Java程序时添加以下JVM参数,解除JDK模块对XStream的访问限制:
--add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED
- IDE环境:在Run Configuration的VM Options中添加上述参数
- 命令行运行:在
java -jar或javac命令前加上这些参数
添加后,saveTree()就能正常序列化测试树,同时你依然可以配置ResultCollector生成测试详情日志。
方案3:自定义样本监听器收集测试日志
实现JMeter的SampleListener接口,自定义收集每个请求的测试结果,输出到控制台或自定义文件:
import org.apache.jmeter.samplers.SampleEvent; import org.apache.jmeter.samplers.SampleListener; import java.io.FileWriter; import java.io.IOException; public class CustomSampleListener implements SampleListener { private FileWriter writer; public CustomSampleListener(String logFilePath) throws IOException { writer = new FileWriter(logFilePath, true); // 写入表头 writer.write("请求URL,响应码,响应时间(ms),响应大小(bytes)\n"); } @Override public void sampleOccurred(SampleEvent event) { try { String url = event.getResult().getUrlAsString(); int responseCode = event.getResult().getResponseCodeAsInt(); long responseTime = event.getResult().getTime(); long responseSize = event.getResult().getBytes(); writer.write(String.format("%s,%d,%d,%d\n", url, responseCode, responseTime, responseSize)); writer.flush(); } catch (IOException e) { e.printStackTrace(); } } @Override public void sampleStarted(SampleEvent event) {} @Override public void sampleStopped(SampleEvent event) {} public void close() throws IOException { writer.close(); } }
然后在测试代码中注册这个监听器:
// 创建测试树后 CustomSampleListener customListener = new CustomSampleListener("custom-test-log.csv"); testPlanTree.add(testPlanTree.getArray()[0], customListener); // 测试结束后关闭文件流 customListener.close();
内容的提问来源于stack exchange,提问作者Agatha Agatha
相关产品推荐
相关产品推荐

