服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 一文搞懂JMeter engine中HashTree的配置问题

一文搞懂JMeter engine中HashTree的配置问题

2021-12-18 14:51HenryXiao8080 Java教程

本文主要介绍了JMeter engine中HashTree的配置,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

一、前言

  • 之前介绍了JMeter engine启动原理,但是里面涉及到HashTree这个类结构没有给大家详细介绍,这边文章就详细介绍JMeter engine里面的HashTree结构具体用来做什么
  • 大家看到下面是JMeter控制台配置截图,是一个标准的菜单形式;菜单形式其实就类似于“树型”的数据结构,而HashTree其实就是一个树型数据结构

一文搞懂JMeter engine中HashTree的配置问题

我们在JMeter控制台导出的jmx文件,是一个xml结构的数据,他其实就是由HashTree生成的,后面我们会讲到

一文搞懂JMeter engine中HashTree的配置问题

 

二、HashTree的用法

首先通过HashTree类介绍,它一个集合类;具备Map结构的功能,而且是一种树型结构

/**
* This class is used to create a tree structure of objects. Each element in the
* tree is also a key to the next node down in the tree. It provides many ways
* to add objects and branches, as well as many ways to retrieve.
* <p>
* HashTree implements the Map interface for convenience reasons. The main
* difference between a Map and a HashTree is that the HashTree organizes the
* data into a recursive tree structure, and provides the means to manipulate
* that structure.
* <p>
* Of special interest is the {@link #traverse(HashTreeTraverser)} method, which
* provides an expedient way to traverse any HashTree by implementing the
* {@link HashTreeTraverser} interface in order to perform some operation on the
* tree, or to extract information from the tree.
*
* @see HashTreeTraverser
* @see SearchByClass
*/
public class HashTree implements Serializable, Map<Object, HashTree>, Cloneable {
}

JMeter常用的HashTree方法(以下图配置为例)

一文搞懂JMeter engine中HashTree的配置问题

//ListedHashTree是HashTree的继承类,可以保证HashTree的顺序性
HashTree tree = new ListedHashTree();
//TestPlan对象,测试计划
TestPlan plan = new TestPlan();
//ThreadGroup对象,线程组
ThreadGroup group = new ThreadGroup();
//创建线程组数结构的对象groupTree
HashTree groupTree = new ListedHashTree();
//表示取样器中的HTTP请求
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
//创建HTTP请求的数结构对象samplerTree
//调用put方法相当于在plan(测试计划)菜单对象下添加group(线程组)子菜单,这样就形成了一种树型结构
HashTree samplerTree = new ListedHashTree();
samplerTree.put(sampler,new ListedHashTree())
//groupTree树结构添加子树samplerTree
groupTree.put(group,samplerTree)
//tree树结构为测试计划对象,添加子树groupTree,这样就形成了上图的层级形式
tree.put(plan, groupTree)
//调用add方法相当于在tree菜单对象下添加同级菜单
tree.add(Object key)

 

三、JMeter源码导出jmx脚本文件介绍

首先在JMeter控制台所有点击事件,都会被ActionRouter中performaAction方法进行监听执行,点击导出按钮,会进入到如图方法通过反射由Save类执行

一文搞懂JMeter engine中HashTree的配置问题

在Save类中执行doAction主要是获取到配置的HashTree

一文搞懂JMeter engine中HashTree的配置问题

当你点击保存的时候,它会创建一个空文件,此时文件没有任何内容

一文搞懂JMeter engine中HashTree的配置问题Save

类的doAction方法最后会调用backupAndSave(e, subTree, fullSave, updateFile)这个是来将创建的空文件写入xml内容的

一文搞懂JMeter engine中HashTree的配置问题

SaveService中saveTree方法,其中JMXSAVERXStream对象,对应的maven坐标如下

<!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
<dependency>
  <groupId>com.thoughtworks.xstream</groupId>
  <artifactId>xstream</artifactId>
  <version>1.4.15</version>
</dependency>

一文搞懂JMeter engine中HashTree的配置问题

 

四、自定义HashTree生成JMeter脚本

首先maven引入以下几个坐标<jmeter.version>5.3</jmeter.version>

      <dependency>
          <groupId>org.apache.jmeter</groupId>
          <artifactId>ApacheJMeter_http</artifactId>
          <version>${jmeter.version}</version>
          <exclusions>
              <exclusion>
                  <groupId>org.apache.logging.log4j</groupId>
                  <artifactId>log4j-slf4j-impl</artifactId>
              </exclusion>
          </exclusions>
      </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>

先创建一个取样器,然后写成HashTree的数据结构

public static ThreadGroup threadGroup;
//创建一个标准的线程组
private static void initThreadGroup(){
  LoopController loopController = new LoopController();
  loopController.setName("LoopController");
  loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
  loopController.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("LoopControlPanel"));
  loopController.setEnabled(true);
  loopController.setLoops(1);
  ThreadGroup group = new ThreadGroup();
  group.setEnabled(true);
  group.setName("ThreadGroup");
  group.setProperty(TestElement.TEST_CLASS, JMeterUtil.readSaveProperties("ThreadGroup"));
  group.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("ThreadGroupGui"));
  group.setProperty(ThreadGroup.ON_SAMPLE_ERROR,"continue");
  group.setProperty(ThreadGroup.IS_SAME_USER_ON_NEXT_ITERATION,true);
  group.setProperty(TestElement.COMMENTS,"");
  group.setNumThreads(1);
  group.setRampUp(1);
  group.setDelay(0);
  group.setDuration(0);
  group.setProperty(ThreadGroup.ON_SAMPLE_ERROR, ThreadGroup.ON_SAMPLE_ERROR_CONTINUE);
  group.setScheduler(false);
  group.setSamplerController(loopController);
  threadGroup = group;
}

创建一个标准的线程组

public static ThreadGroup threadGroup;
//创建一个标准的线程组
private static void initThreadGroup(){
  LoopController loopController = new LoopController();
  loopController.setName("LoopController");
  loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
  loopController.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("LoopControlPanel"));
  loopController.setEnabled(true);
  loopController.setLoops(1);
  ThreadGroup group = new ThreadGroup();
  group.setEnabled(true);
  group.setName("ThreadGroup");
  group.setProperty(TestElement.TEST_CLASS, JMeterUtil.readSaveProperties("ThreadGroup"));
  group.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("ThreadGroupGui"));
  group.setProperty(ThreadGroup.ON_SAMPLE_ERROR,"continue");
  group.setProperty(ThreadGroup.IS_SAME_USER_ON_NEXT_ITERATION,true);
  group.setProperty(TestElement.COMMENTS,"");
  group.setNumThreads(1);
  group.setRampUp(1);
  group.setDelay(0);
  group.setDuration(0);
  group.setProperty(ThreadGroup.ON_SAMPLE_ERROR, ThreadGroup.ON_SAMPLE_ERROR_CONTINUE);
  group.setScheduler(false);
  group.setSamplerController(loopController);
  threadGroup = group;
}

创建一个标准的测试计划

public static TestPlan testPlan;
//创建一个标准的测试计划
private static void initTestPlan() {
  TestPlan plan = new TestPlan();
  //设置测试计划属性及内容,最后都会转为xml标签的属性及内容
  plan.setProperty(TestElement.NAME, "测试计划");
  plan.setProperty(TestElement.TEST_CLASS, JMeterUtil.readSaveProperties("TestPlan"));
  plan.setProperty(TestElement.GUI_CLASS, JMeterUtil.readSaveProperties("TestPlanGui"));
  plan.setEnabled(true);
  plan.setComment("");
  plan.setFunctionalMode(false);
  plan.setTearDownOnShutdown(true);
  plan.setSerialized(false);
  plan.setProperty("TestPlan.user_define_classpath","");
  plan.setProperty("TestPlan.user_defined_variables","");
  plan.setUserDefinedVariables(new Arguments());
  testPlan = plan;
}

开始封装成一个HashTree的配置

//先创建一个测试计划hashtree对象
HashTree hashTree = new ListedHashTree();
//在创建一个线程组threaddGroupTree对象
HashTree threadGroupTree = new ListedHashTree();
//HttpRequestConfig为HTTP对应的请求头、请求体等信息数据,传入httpToHashTree静态方法获取到取样器的HashTree数据结构,源码上图已分享
HashTree httpConfigTree = XXClass.httpToHashTree(HttpRequestConfig httpRequestData)
//threadGroupTree添加子菜单httpConfigTree对象
threadGroupTree.put(group, httpConfigTree);
//测试计划hashTree添加子菜单threadGroupTree对象
hashTree.put(JMeterTestPlanConfigService.testPlan, threadGroupTree);

HashTree写好后,调用JMeter原生方法SaveService.saveTree(hashTree,outStream);生成对应的xml

如果直接调用的话生成的xml格式会形成如下图所示,而非JMeter原生导出jmx形式,这种文件结构JMeter控制台读取会报错,识别不了

一文搞懂JMeter engine中HashTree的配置问题

一文搞懂JMeter engine中HashTree的配置问题

后面阅读SaveService源码才明白,生成xml文件之前会先初始化静态代码块内容,初始化属性

一文搞懂JMeter engine中HashTree的配置问题
一文搞懂JMeter engine中HashTree的配置问题

过程中会调用JMeterUtils中的findFile方法来寻找saveservice.properties文件

一文搞懂JMeter engine中HashTree的配置问题

由于SaveService 中都是静态方法无法重写,所以根据最后调用JMeterUtils中的findFile方法来寻找saveservice.properties有两种解决方案

方案一 :不推荐,在项目根目录下存放saveservice.properties,这样findFile方法就能拿到,但是这样不好,因为maven打包的时候该文件会打不进去,至少我springboot项目是遇到这样的问题

方案二:推荐,创建一个临时文件命名为saveservice.properties,然后提前将saveservice.properties配置读取到临时文件中,这样在调用JMeterUtils中的findFile方法同样能够找到配置,成功解决SaveService初始化属性导致的问题,具体代码如下

private void hashTreeToXML(HashTree hashTree,PressureConfigInfo configInfo){
  FileOutputStream outStream = null;
  File file = new File("temp.jmx");
  File tempFile = null;
  try {
  	//创建一个临时的saveservice.properties文件
      tempFile = new File("saveservice.properties");
      InputStream is = JMeterUtil.class.getResource("/jmeter/saveservice.properties").openStream();
      //将配置文件写入临时文件中
      FileUtil.writeFromStream(is,tempFile);
      outStream = new FileOutputStream(file);
      //调用saveTree成功转为xml
      SaveService.saveTree(hashTree,outStream);
      String xmlContent = FileUtil.readUtf8String(file);
      configInfo.setFile(xmlContent.getBytes());
  } catch (IOException e) {
      e.printStackTrace();
  }finally {
      try {
          FileUtils.forceDelete(file);
          FileUtils.forceDelete(tempFile);
      } catch (IOException e) {
          e.printStackTrace();
      }
  }
}

最后生成的xml文件结构如下图,通过JMeter控制台也能成功打开识别

一文搞懂JMeter engine中HashTree的配置问题

到此这篇关于一文搞懂JMeter engine中HashTree的配置问题的文章就介绍到这了,更多相关JMeter engine中HashTree配置内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/weixin_40686603/article/details/114589428

延伸 · 阅读

精彩推荐
  • Java教程小米推送Java代码

    小米推送Java代码

    今天小编就为大家分享一篇关于小米推送Java代码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    富贵稳中求8032021-07-12
  • Java教程20个非常实用的Java程序代码片段

    20个非常实用的Java程序代码片段

    这篇文章主要为大家分享了20个非常实用的Java程序片段,对java开发项目有所帮助,感兴趣的小伙伴们可以参考一下 ...

    lijiao5352020-04-06
  • Java教程Java BufferWriter写文件写不进去或缺失数据的解决

    Java BufferWriter写文件写不进去或缺失数据的解决

    这篇文章主要介绍了Java BufferWriter写文件写不进去或缺失数据的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望...

    spcoder14552021-10-18
  • Java教程xml与Java对象的转换详解

    xml与Java对象的转换详解

    这篇文章主要介绍了xml与Java对象的转换详解的相关资料,需要的朋友可以参考下...

    Java教程网2942020-09-17
  • Java教程Java实现抢红包功能

    Java实现抢红包功能

    这篇文章主要为大家详细介绍了Java实现抢红包功能,采用多线程模拟多人同时抢红包,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    这篇文章主要介绍了Java使用SAX解析xml的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java8中Stream使用的一个注意事项

    Java8中Stream使用的一个注意事项

    最近在工作中发现了对于集合操作转换的神器,java8新特性 stream,但在使用中遇到了一个非常重要的注意点,所以这篇文章主要给大家介绍了关于Java8中S...

    阿杜7482021-02-04
  • Java教程升级IDEA后Lombok不能使用的解决方法

    升级IDEA后Lombok不能使用的解决方法

    最近看到提示IDEA提示升级,寻思已经有好久没有升过级了。升级完毕重启之后,突然发现好多错误,本文就来介绍一下如何解决,感兴趣的可以了解一下...

    程序猿DD9332021-10-08