目标
- 1.需要利用jmeter做一个压测平台,读取我们自定义的jmx文件模板,把用户传入的数据将文件内容中的
${requestBody}
或者其他的一些自定义模板变量进行替换。- 2.将jmx文件丢给jmeter引擎执行
- 3.收集压测结果
如图:
引入Maven
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_core</artifactId>
<version>${jmeter.version}</version>
</dependency>
<!--jMeter component-->
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_components</artifactId>
<version>${jmeter.version}</version>
</dependency>
<!--jMeter Http包-->
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_http</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_functions</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_jdbc</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_tcp</artifactId>
<version>${jmeter.version}</version>
</dependency>
截止发文,当前最新版本的jmeter是5.4.1
思路
- 1.初始化jmeter
- 2.读取自定义的jmx模板
- 3.copy一份jmx模板,不能改变模板内容,只能在复制体上操作,因为模板还要再继续使用的
- 4.对复制体内容进行替换
- 5.更改复制体文件后缀为jmx,jmeter引擎只能接受jmx后缀的文件
- 6.将jmx文件丢给jmeter使用
- 7.收集压测结果
public void testReferenceLocal() {
/*********** 1.jmeter 初始化 ************/
// jemter 引擎
StandardJMeterEngine standardJMeterEngine = new StandardJMeterEngine();
// 设置不适用gui的方式调用jmeter
System.setProperty(JMeter.JMETER_NON_GUI, "true");
JMeterUtils.loadJMeterProperties(jMeter_home_path + "/bin/jmeter.properties");
JMeterUtils.setJMeterHome(jMeter_home_path);
JMeterUtils.initLocale();
File tempFile = null;
File jmxFile = null;
try {
SaveService.loadProperties();
/*********** 2.对模板文件进行操作 ************/
// 模板文件位置 该文件是一个jmx文件
String templateFilePath = "/Users/wushuaiping/apache-jmeter-5.4.1/bin/HTTP请求.ftl";
// copy文件
File templateFile = new File(templateFilePath);
String templateFileName = templateFile.getName();
// 真实环境需要考虑文件重复
tempFile = File.createTempFile(templateFileName.substring(0, templateFileName.lastIndexOf(".")) + "-userId-" + System.currentTimeMillis(), ".ftl");
// 真实环境中可以做缓存,将该临时文件缓存起来,这样就不用每次就去copy操作了消耗机器性能。
FileUtils.copyFile(templateFile, tempFile);
/*********** 3.对copy后的文件进行内容替换 ************/
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
configuration.setDefaultEncoding("utf-8");
String tempFilePath = tempFile.getPath();
configuration.setDirectoryForTemplateLoading(new File(tempFilePath.substring(0, tempFilePath.lastIndexOf(File.separator) + 1)));
Template template = configuration.getTemplate(tempFile.getName(), "utf-8");
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempFile),
StandardCharsets.UTF_8), 10240);
Map<String, String> dataMap = new HashMap<>();
Map<String, String> user = new HashMap<>();
user.put("name", "Wsp");
user.put("age", "18");
dataMap.put("requestBody", StringEscapeUtils.escapeXml(JSON.toJSONString(user)));
template.process(dataMap, out);
out.close();
/*********** 4.内容替换完成,更改文件后缀为jmx,丢给jmeter执行 ************/
String jmxSuffixTempFile = tempFile.getPath().substring(0, tempFile.getPath().lastIndexOf(".")) + ".jmx";
jmxFile = new File(jmxSuffixTempFile);
tempFile.renameTo(jmxFile);
String fileToString = FileUtils.readFileToString(tempFile, "utf-8");
TemplateUtil.render(fileToString, dataMap);
// 使用jmeter进行压测
HashTree testPlanTree = SaveService.loadTree(jmxFile);
//4.create Summariser.java
Summariser summer = null;
String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");
if (summariserName.length() > 0) {
summer = new Summariser(summariserName);
}
ResultCollector resultCollector = new ResultCollector(summer);
testPlanTree.add(testPlanTree.getArray(), resultCollector);
standardJMeterEngine.configure(testPlanTree);
standardJMeterEngine.run();
/*********** 5.获取压测结果 ************/
SummariserRunningSample total = summer.getTotal();
System.out.println(total);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (tempFile != null) {
tempFile.deleteOnExit();
}
if (jmxFile != null) {
jmxFile.deleteOnExit();
}
}
}
SummariserRunningSample total = summer.getTotal();
对于该段代码,使用jmeter的api是无法获取的,所以我们需要利用jvm的加载机制做一些操作。
我们在项目中定义一个名为org.apache.jmeter.reporters
的包。
然后拷贝jmeter的Summariser
类和SummariserRunningSample
类到自定义的包中。在Summariser
中新增方法:
public SummariserRunningSample getTotal(){
return myTotals.total;
}
把SummariserRunningSample
类改为public
修饰,
把Summariser
类中的内部静态类Totals
改为public修饰,把内部静态类Totals
中的total
常量改为public修饰。
最后你就能愉快在Java中获取Jmeter的结果集了。
其他
关于Jmeter除了我写的这种方式在Java中做压测外,还有一种方式是通过Jmeter的HashTree来组装数据,HashTree其实就是Java代码版本的jmx文件。不过组装比较麻烦,我这两天还在研究如果通过HashTree来组装,等研究出来后,我再做分享。