Java 代码调用 Jmeter

一、Jmeter的简介

Jmeter一款开源的压力测试工具,而这款开源的测试工具是基于Java开发。Jmeter最初的设计是为了web的性能测试。而在后面扩展了很多种类的测试。

Jmeter是基于Java编写,所以使用时需要安装jdk

二、Jmeter负载测试和性能测试种类

1.Web - HTTP, HTTPS (Java, NodeJS, PHP, ASP.NET, …)
2.SOAP / REST Webservices
3.FTP
4.Database via JDBC
5.LDAP
6.Message-oriented middleware (MOM) via JMS
7.Mail - SMTP(S), POP3(S) and IMAP(S)
8.Native commands or shell scripts
9.TCP
10.Java Objects

三、Jmeter基本组件简介

我们这里只讲解使用到的一些组件。而其他组件可以到Jmeter的官网了解(https://jmeter.apache.org/),在Jmeter下每个组件都是节点的方式进行配置。如我们在图形化界面中,都会有一个TestPlan的根节点,其他控件都添加在根节点下。

3.1.TestPlan
测试计划,每一个测试都为一个测试计划。

2.ThreadGroup:是一个测试计划的开始。所有的controller、sampler必须在线程组下。不过有一些特许的控件如Listeners可以直接在TestPlan下。

3.sampler:采样器,也就是我们各种性能测试和负载测试的收集器。如:http采样器:HTTPSampler等

4.Controller:主要用于压力测试逻辑的处理,如我们这里使用了LoopController进行控制线程的循环次数,是永久还是循环压力测试多次。

四、Jmeter的调用方式

调用Jmeter有5中方式:

五、使用JAVA调用jmeter

一、创建项目

我们这里使用了Ecplise IDE创建Maven项目。

二、导入Jmeter的包

 我们这里演示使用的是http的压力测试。所以会用到ApacheJMeter_http的包和ApacheJMeter_core的包
  <!--jmeter核心包-->
       <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_core</artifactId>
            <version>4.0</version>
        </dependency>
  <!--jmeter组件包-->
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_components</artifactId>
            <version>4.0</version>
        </dependency>
  <!--jmeter Http包-->
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_http</artifactId>
            <version>4.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

三、演示代码

package com.study;

import java.io.File;

import org.apache.jmeter.JMeter;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;

public class TestPlanLauncher {

    public static void main(String[] args) {
        // jemter 引擎
        StandardJMeterEngine standardJMeterEngine = new StandardJMeterEngine();
        // 设置不适用gui的方式调用jmeter
        System.setProperty(JMeter.JMETER_NON_GUI, "true");
        // 设置jmeter.properties文件,我们将jmeter文件存放在resources中,通过classload
        String path = TestPlanLauncher.class.getClassLoader().getResource("jmeter.properties").getPath();
        File jmeterPropertiesFile = new File(path);
        if (jmeterPropertiesFile.exists()) {
            JMeterUtils.loadJMeterProperties(jmeterPropertiesFile.getPath());
            HashTree testPlanTree = new HashTree();
            // 创建测试计划
            TestPlan testPlan = new TestPlan("Create JMeter Script From Java Code");
            // 创建http请求收集器
            HTTPSamplerProxy examplecomSampler = createHTTPSamplerProxy();
            // 创建循环控制器
            LoopController loopController = createLoopController();
            // 创建线程组
            ThreadGroup threadGroup = createThreadGroup();
            // 线程组设置循环控制
            threadGroup.setSamplerController(loopController);
            // 将测试计划添加到测试配置树种
            HashTree threadGroupHashTree = testPlanTree.add(testPlan, threadGroup);
            // 将http请求采样器添加到线程组下
            threadGroupHashTree.add(examplecomSampler);
            //增加结果收集
            Summariser summer = null;
            String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");
            if (summariserName.length() > 0) {
                summer = new Summariser(summariserName);
            }
            ResultCollector logger = new ResultCollector(summer);
            testPlanTree.add(testPlanTree.getArray(), logger);
            
            // 配置jmeter
            standardJMeterEngine.configure(testPlanTree);
            // 运行
            standardJMeterEngine.run();
        }
    }

    /**
     * 创建线程组
     * 
     * @return
     */
    public static ThreadGroup createThreadGroup() {
        ThreadGroup threadGroup = new ThreadGroup();
        threadGroup.setName("Example Thread Group");
        threadGroup.setNumThreads(1);
        threadGroup.setRampUp(0);
        threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
        threadGroup.setScheduler(true);
        threadGroup.setDuration(60);
        threadGroup.setDelay(0);
        return threadGroup;
    }

    /**
     * 创建循环控制器
     * 
     * @return
     */
    public static LoopController createLoopController() {
        // Loop Controller
        LoopController loopController = new LoopController();
        loopController.setLoops(-1);
        loopController.setContinueForever(true);
        loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
        loopController.initialize();
        return loopController;
    }

    /**
     * 创建http采样器
     * 
     * @return
     */
    public static HTTPSamplerProxy createHTTPSamplerProxy() {
        HeaderManager headerManager = new HeaderManager();
        headerManager.setProperty("Content-Type", "multipart/form-data");
        HTTPSamplerProxy httpSamplerProxy = new HTTPSamplerProxy();
        httpSamplerProxy.setDomain("www.baidu.com");
        httpSamplerProxy.setPort(80);
        httpSamplerProxy.setPath("/");
        httpSamplerProxy.setMethod("GET");
        httpSamplerProxy.setConnectTimeout("5000");
        httpSamplerProxy.setUseKeepAlive(true);
        httpSamplerProxy.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
        httpSamplerProxy.setHeaderManager(headerManager);
        return httpSamplerProxy;
    }
}

三、详讲

3.1 Jmeter引擎StandardJMeterEngine

StandardJMeterEngine是Java调用Jmeter的入口。

3.2 Jmeter.properties文件
  • 指定Jmeter.properties文件,Jmeter.properties文件主要用于Jmeter全局基础配置。我们可以根据自己的需求进行修改配置文件。
    例如我们需要进行分布式压力测试的情况下,我们就需要在remote_hosts添加远程的IP。
  • 指定jmeter.properties文件的方式,我们可以通过源码的分析发现加载配置Jmeter.properties配置文件,先从指定的文件中查找,如果查找不到jmeter.properties文件,会在org/apache/jmeter/jmeter.properties查找查找。也就是说我们可以将配置文件存放在org/apache/jmeter路径下或者指定配置文件。
    public static void loadJMeterProperties(String file) {
        Properties p = new Properties(System.getProperties());
        InputStream is = null;
        try {
            File f = new File(file);
            is = new FileInputStream(f);
            p.load(is);
        } catch (IOException e) {
            try {
                is = ClassLoader.getSystemResourceAsStream(
                        "org/apache/jmeter/jmeter.properties"); // $NON-NLS-1$
                if (is == null) {
                    throw new RuntimeException("Could not read JMeter properties file:" + file);
                }
                p.load(is);
            } catch (IOException ex) {
                throw new RuntimeException("Could not read JMeter properties file:" + file);
            }
        } finally {
            JOrphanUtils.closeQuietly(is);
        }
        appProperties = p;
    }
3.3 HashTree

我们在使用Jmeter的图形化界面的时候,我们可以看出所有组件都是添加在TestPlan下。而在使用非图形化界面的时,我们的StandardJMeterEngine通过configure方法来进行配置我们的TestPlan、ThreadGroup、LoopController等组件,因此需要创建HashTree。

3.4 TestPlan

我们在使用图形化界面都知道所有组件都是存放在TestPlan中,所以我们需要创建一个TestPlan用于存放组件。

3.5 HTTPSamplerProxy

HTTPSamplerProxy是HTTP采样器,在Jmeter中提供做了多种采样器,我们可以根据采样数据来确定到底使用哪一个采样器。在压力测试时,是通过Thread Group来进行创建线程进行压力测试的。每个线程都需要通过Sampler来确定去并发访问,因此Sampler是存放在Thread Group下。


image.png
3.6 LoopController

LoopController是一个压力循环次数的控制器。我们通常会配置ThreadGroup进行使用,例如我们在Thread Group中设置持续5秒,并发量50的情况下,我们会这是LoopController为永久循环。我们需要注意:永久循环的情况下loops应设置为-1.

 loopController.setLoops(-1);
 loopController.setContinueForever(true);

注意:Controller是存放在Thread Group下。

3.7 ThreadGroup

在Jmeter下是通过线程方式去并发访问,线程管理Jmeter通过ThreadGroup来控制线程的数量和线程的创建、线程持续访问的时间。

3.8 ResultCollector
  • ResultCollector是一个结果的收集器,ResultController收集请求结果是通过监听的方式进行收集结果。
  • 通过查看ResultController的源码发现其实现了SampleListener接口,并且调用sampleOccurred方法处理每个sampler的结果。
    /**
     * When a test result is received, display it and save it.
     *
     * @param event
     *            the sample event that was received
     */
    @Override
    public void sampleOccurred(SampleEvent event) {
        SampleResult result = event.getResult();

        if (isSampleWanted(result.isSuccessful())) {
            sendToVisualizer(result);
            if (out != null && !isResultMarked(result) && !this.isStats) {
                SampleSaveConfiguration config = getSaveConfig();
                result.setSaveConfig(config);
                try {
                    if (config.saveAsXml()) {
                        SaveService.saveSampleResult(event, out);
                    } else { // !saveAsXml
                        String savee = CSVSaveService.resultToDelimitedString(event);
                        out.println(savee);
                    }
                } catch (Exception err) {
                    log.error("Error trying to record a sample", err); // should throw exception back to caller
                }
            }
        }

        if(summariser != null) {
            summariser.sampleOccurred(event);
        }
    }
  • 在ResultController.sampleOccurred方法中我们可以看到summariser不为空的情况下调用summariser的sampleOccurred方法,从summariser.sampleOccurred方法我们可以知道summariser一定是实现了SampleListener接口。
public class Summariser extends AbstractTestElement
    implements Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable {
  • 在多线程的情况下,Jmeter会对Controller、Sampler等组件为每个线程拷贝一份对象。而对于组件ResultCollector是不拷贝对象。

/**
 * This class handles all saving of samples.
 * The class must be thread-safe because it is shared between threads (NoThreadClone).
 */
public class ResultCollector extends AbstractListenerElement implements SampleListener, Clearable, Serializable,
        TestStateListener, Remoteable, NoThreadClone {

Reference:
https://jmeter.apache.org/api/index.html
https://www.blazemeter.com/blog/5-ways-launch-jmeter-test-without-using-jmeter-gui
https://jmeter.apache.org/usermanual/get-started.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • 主要文体来自 CDNS:https://www.cnblogs.com/ceshisanren/p/5639895...
    Amano阅读 10,858评论 3 27
  • 大学是一个成长的图标,一步步前进到这里,付出了很多——时间,精力,重要的是青春。我们用一整个青春奋斗一个大学,...
    薄荷微凉々阅读 281评论 0 0
  • 不要等到明天,明天太遥远,今天就行动。 须读:看完该文章你能做什么? NSArray文件读写 学习前:你必须会什么...
    liyuhong阅读 267评论 0 0
  • 最近一直下雨,一下雨地铁就很挤,湿答答的雨伞把你的裤子弄湿,你却无处可躲。前面人的长发从你脸上扫过,后面人的书包靠...
    南瓜土豆饼阅读 121评论 0 3
  • 今晚吃过饭和我爸散步,突然被问道现在最好的朋友是谁?我愣了一下,久久给不出答案。 这个问题的本身是简单的,可就是找...
    你有什么不会的啊阅读 359评论 0 0