• JMeter5.0核心源码浅析[转]


    【转自:https://blog.csdn.net/zuozewei/article/details/85042829】

    源码下载地址:
    https://github.com/apache/jmeter
    废话不多说,下面进入正题~

    一、源码结构

    1. 工程目录

     

    2. 源码目录

     

    3. 源码分析

    运行机制

     

    • HashTree 是 JMeter 执行测试依赖的数据结构,在执行测试之前进行配置测试数据,HashTree将数据组织到一个递归树结构中,并提供了操作该结构的方法
    • StandardJMeterEngine 执行JMeter 测试 ,直接用于本地 GUI 和非 GUI 调用,或者在服务器模式下运行时由 RemoteJMeterEngineImpl 启动
    • JMeterEngine 接口被运行 JMeter的测试类实现,此接口共8个方法,JMeterEngine本质就是一个线程。

    二、代码分析

    此处以非GUI模式运行JMeter为例,了解下JMeter的运行机制。首先我们找到入口类 NewDriver。

     /**
         * The main program which actually runs JMeter.
         * mian方法
         * @param args
         *            the command line arguments
         */
        public static void main(String[] args) {
            if(!EXCEPTIONS_IN_INIT.isEmpty()) {
                System.err.println("Configuration error during init, see exceptions:"+exceptionsToString(EXCEPTIONS_IN_INIT));
            } else {
                Thread.currentThread().setContextClassLoader(loader);
    
                setLoggingProperties(args);
    
                try {
                    // 加载JMeter类
                    Class<?> initialClass = loader.loadClass("org.apache.jmeter.JMeter");// $NON-NLS-1$
                    // 获取JMeter类实例
                    Object instance = initialClass.getDeclaredConstructor().newInstance();
                    // 获取start方法类型实例
                    Method startup = initialClass.getMethod("start", new Class[] { new String[0].getClass() });// $NON-NLS-1$
                    // 反射调用JMeter类的start方法
                    startup.invoke(instance, new Object[] { args });
                } catch(Throwable e){ // NOSONAR We want to log home directory in case of exception
                    e.printStackTrace(); // NOSONAR No logger at this step
                    System.err.println("JMeter home directory was detected as: "+JMETER_INSTALLATION_DIRECTORY);
                }
            }
        }

    很明显,这里是通过反射调用 JMeter 类的 start 方法。
    接下来我们看下 start 方法

     /**
         * Takes the command line arguments and uses them to determine how to
         * startup JMeter.
         * 根据命令行执行不同的操作
         * 主要功能为:1)startgui 2)startnogui
         *
         * Called reflectively by {@link NewDriver#main(String[])}
         * @param args The arguments for JMeter
         */
        public void start(String[] args) {
            // 解析命令号参数的类
            CLArgsParser parser = new CLArgsParser(args, options);
            // 错误信息
            String error = parser.getErrorString();
            if (error == null){// Check option combinations 检查选项组合
                boolean gui = parser.getArgumentById(NONGUI_OPT)==null;
                boolean nonGuiOnly = parser.getArgumentById(REMOTE_OPT)!=null
                                   || parser.getArgumentById(REMOTE_OPT_PARAM)!=null
                                   || parser.getArgumentById(REMOTE_STOP)!=null;
                if (gui && nonGuiOnly) {
                    error = "-r and -R and -X are only valid in non-GUI mode";
                }
            }
            // 输出错误信息
            if (null != error) {
                System.err.println("Error: " + error);//NOSONAR
                System.out.println("Usage");//NOSONAR
                System.out.println(CLUtil.describeOptions(options).toString());//NOSONAR
                // repeat the error so no need to scroll back past the usage to see it
                System.out.println("Error: " + error);//NOSONAR
                return;
            }
            try {
                // 初始化配置,同时初始化JMeter日志
                initializeProperties(parser); // Also initialises JMeter logging
    
                Thread.setDefaultUncaughtExceptionHandler(
                        (Thread t, Throwable e) -> {
                        if (!(e instanceof ThreadDeath)) {
                            log.error("Uncaught exception: ", e);
                            System.err.println("Uncaught Exception " + e + ". See log file for details.");//NOSONAR
                        }
                });
    
                if (log.isInfoEnabled()) {
                    log.info(JMeterUtils.getJMeterCopyright());
                    log.info("Version {}", JMeterUtils.getJMeterVersion());
                    log.info("java.version={}", System.getProperty("java.version"));//$NON-NLS-1$ //$NON-NLS-2$
                    log.info("java.vm.name={}", System.getProperty("java.vm.name"));//$NON-NLS-1$ //$NON-NLS-2$
                    log.info("os.name={}", System.getProperty("os.name"));//$NON-NLS-1$ //$NON-NLS-2$
                    log.info("os.arch={}", System.getProperty("os.arch"));//$NON-NLS-1$ //$NON-NLS-2$
                    log.info("os.version={}", System.getProperty("os.version"));//$NON-NLS-1$ //$NON-NLS-2$
                    log.info("file.encoding={}", System.getProperty("file.encoding"));//$NON-NLS-1$ //$NON-NLS-2$
                    log.info("Max memory     ={}", Runtime.getRuntime().maxMemory());
                    log.info("Available Processors ={}", Runtime.getRuntime().availableProcessors());
                    log.info("Default Locale={}", Locale.getDefault().getDisplayName());
                    log.info("JMeter  Locale={}", JMeterUtils.getLocale().getDisplayName());
                    log.info("JMeterHome={}", JMeterUtils.getJMeterHome());
                    log.info("user.dir  ={}", System.getProperty("user.dir"));//$NON-NLS-1$ //$NON-NLS-2$
                    log.info("PWD       ={}", new File(".").getCanonicalPath());//$NON-NLS-1$
                    log.info("IP: {} Name: {} FullName: {}", JMeterUtils.getLocalHostIP(), JMeterUtils.getLocalHostName(),
                            JMeterUtils.getLocalHostFullName());
                }
                setProxy(parser);
    
                updateClassLoader();
                if (log.isDebugEnabled())
                {
                    String jcp=System.getProperty("java.class.path");// $NON-NLS-1$
                    String[] bits = jcp.split(File.pathSeparator);
                    log.debug("ClassPath");
                    for(String bit : bits){
                        log.debug(bit);
                    }
                }
    
                // Set some (hopefully!) useful properties 设置属性
                long now=System.currentTimeMillis();
                JMeterUtils.setProperty("START.MS",Long.toString(now));// $NON-NLS-1$
                Date today=new Date(now); // so it agrees with above
                JMeterUtils.setProperty("START.YMD",new SimpleDateFormat("yyyyMMdd").format(today));// $NON-NLS-1$ $NON-NLS-2$
                JMeterUtils.setProperty("START.HMS",new SimpleDateFormat("HHmmss").format(today));// $NON-NLS-1$ $NON-NLS-2$
    
                // 判断
                if (parser.getArgumentById(VERSION_OPT) != null) {
                    displayAsciiArt();
                } else if (parser.getArgumentById(HELP_OPT) != null) {
                    displayAsciiArt();
                    System.out.println(JMeterUtils.getResourceFileAsText("org/apache/jmeter/help.txt"));//NOSONAR $NON-NLS-1$
                } else if (parser.getArgumentById(OPTIONS_OPT) != null) {
                    displayAsciiArt();
                    System.out.println(CLUtil.describeOptions(options).toString());//NOSONAR
                } else if (parser.getArgumentById(SERVER_OPT) != null) {
                    // Start the server 启动服务
                    try {
                        RemoteJMeterEngineImpl.startServer(RmiUtils.getRmiRegistryPort()); // $NON-NLS-1$
                        startOptionalServers();
                    } catch (Exception ex) {
                        System.err.println("Server failed to start: "+ex);//NOSONAR
                        log.error("Giving up, as server failed with:", ex);
                        throw ex;
                    }
                } else {
                    String testFile=null;
                    CLOption testFileOpt = parser.getArgumentById(TESTFILE_OPT);
                    if (testFileOpt != null){
                        testFile = testFileOpt.getArgument();
                        if (USE_LAST_JMX.equals(testFile)) {
                            testFile = LoadRecentProject.getRecentFile(0);// most recent
                        }
                    }
                    CLOption testReportOpt = parser.getArgumentById(REPORT_GENERATING_OPT);
                    if (testReportOpt != null) { // generate report from existing file 从现有文件生成报告
                        String reportFile = testReportOpt.getArgument();
                        extractAndSetReportOutputFolder(parser, false);
                        ReportGenerator generator = new ReportGenerator(reportFile, null);
                        generator.generate();
                    } else if (parser.getArgumentById(NONGUI_OPT) == null) { // not non-GUI => GUI
                        // 在GUI模式下执行
                        startGui(testFile);
                        startOptionalServers();
                    } else { // NON-GUI must be true 必须为无GUI模式
                        extractAndSetReportOutputFolder(parser, deleteResultFile);
                        
                        CLOption rem = parser.getArgumentById(REMOTE_OPT_PARAM);
                        if (rem == null) {
                            rem = parser.getArgumentById(REMOTE_OPT);
                        }
                        CLOption jtl = parser.getArgumentById(LOGFILE_OPT);
                        String jtlFile = null;
                        if (jtl != null) {
                            jtlFile = processLAST(jtl.getArgument(), ".jtl"); // $NON-NLS-1$
                        }
                        CLOption reportAtEndOpt = parser.getArgumentById(REPORT_AT_END_OPT);
                        if(reportAtEndOpt != null && jtlFile == null) {
                            throw new IllegalUserActionException(
                                    "Option -"+ ((char)REPORT_AT_END_OPT)+" requires -"+((char)LOGFILE_OPT )+ " option");
                        }
                        // 无GUI执行
                        startNonGui(testFile, jtlFile, rem, reportAtEndOpt != null);
                        startOptionalServers();
                    }
                }
            } catch (IllegalUserActionException e) {// NOSONAR
                System.out.println("Incorrect Usage:"+e.getMessage());//NOSONAR
                System.out.println(CLUtil.describeOptions(options).toString());//NOSONAR
            } catch (Throwable e) { // NOSONAR
                log.error("An error occurred: ", e);
                System.out.println("An error occurred: " + e.getMessage());//NOSONAR
                // FIXME Should we exit here ? If we are called by Maven or Jenkins
                System.exit(1);
            }
        }

    start 方法主要还是根据命令执行不同的启动方法
    无 GUI 方法启动

       private void startNonGui(String testFile, String logFile, CLOption remoteStart, boolean generateReportDashboard)
                throws IllegalUserActionException, ConfigurationException {
            // add a system property so samplers can check to see if JMeter
            // is running in NonGui mode
            System.setProperty(JMETER_NON_GUI, "true");// $NON-NLS-1$
            JMeter driver = new JMeter();// TODO - why does it create a new instance?
            driver.remoteProps = this.remoteProps;
            driver.remoteStop = this.remoteStop;
            driver.deleteResultFile = this.deleteResultFile;
            
            PluginManager.install(this, false);
    
            String remoteHostsString = null;
            if (remoteStart != null) {
                remoteHostsString = remoteStart.getArgument();
                if (remoteHostsString == null) {
                    remoteHostsString = JMeterUtils.getPropDefault(
                            "remote_hosts", //$NON-NLS-1$
                            "127.0.0.1");//NOSONAR $NON-NLS-1$ 
                }
            }
            if (testFile == null) {
                throw new IllegalUserActionException("Non-GUI runs require a test plan");
            }
            // 运行场景
            driver.runNonGui(testFile, logFile, remoteStart != null, remoteHostsString, generateReportDashboard);
        }

    GUI方法启动

     /**
         * Starts up JMeter in GUI mode
         * JMeter GUI启动
         */
        private void startGui(String testFile) {
            System.out.println("================================================================================");//NOSONAR
            System.out.println("Don't use GUI mode for load testing !, only for Test creation and Test debugging.");//NOSONAR
            System.out.println("For load testing, use NON GUI Mode:");//NOSONAR
            System.out.println("   jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]");//NOSONAR
            System.out.println("& increase Java Heap to meet your test requirements:");//NOSONAR
            System.out.println("   Modify current env variable HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m" in the jmeter batch file");//NOSONAR
            System.out.println("Check : https://jmeter.apache.org/usermanual/best-practices.html");//NOSONAR
            System.out.println("================================================================================");//NOSONAR
    
            // 设置加载进度条  splash.setProgress(10/30/60/90/100)
            SplashScreen splash = new SplashScreen();
            splash.showScreen();
            String jMeterLaf = LookAndFeelCommand.getJMeterLaf();
            try {
                log.info("Setting LAF to: {}", jMeterLaf);
                UIManager.setLookAndFeel(jMeterLaf);
            } catch (Exception ex) {
                log.warn("Could not set LAF to: {}", jMeterLaf, ex);
            }
            splash.setProgress(10);
            JMeterUtils.applyHiDPIOnFonts();
            PluginManager.install(this, true);
    
            JMeterTreeModel treeModel = new JMeterTreeModel();
            splash.setProgress(30);
            JMeterTreeListener treeLis = new JMeterTreeListener(treeModel);
            final ActionRouter instance = ActionRouter.getInstance();
            instance.populateCommandMap(); //这个方法会去寻找<project>/lib/ext 下所有的jar
            splash.setProgress(60);
            treeLis.setActionHandler(instance);
            GuiPackage.initInstance(treeLis, treeModel);
            splash.setProgress(80);
            MainFrame main = new MainFrame(treeModel, treeLis);
            splash.setProgress(100);
            ComponentUtil.centerComponentInWindow(main, 80);
            main.setLocationRelativeTo(splash);
            main.setVisible(true);
            main.toFront();
            instance.actionPerformed(new ActionEvent(main, 1, ActionNames.ADD_ALL));
            if (testFile != null) {
                try {
                    File f = new File(testFile);
                    log.info("Loading file: {}", f);
                    FileServer.getFileServer().setBaseForScript(f);
    
                    HashTree tree = SaveService.loadTree(f);
    
                    GuiPackage.getInstance().setTestPlanFile(f.getAbsolutePath());
    
                    Load.insertLoadedTree(1, tree);
                } catch (ConversionException e) {
                    log.error("Failure loading test file", e);
                    JMeterUtils.reportErrorToUser(SaveService.CEtoString(e));
                } catch (Exception e) {
                    log.error("Failure loading test file", e);
                    JMeterUtils.reportErrorToUser(e.toString());
                }
            } else {
                JTree jTree = GuiPackage.getInstance().getMainFrame().getTree();
                TreePath path = jTree.getPathForRow(0);
                jTree.setSelectionPath(path);
                FocusRequester.requestFocus(jTree);
            }
            splash.setProgress(100);
            splash.close();
        }

    在来看下 runNonGui 方法,主要功能是执行脚本。

    // run test in batch mode  批处理运行测试
        private void runNonGui(String testFile, String logFile, boolean remoteStart, String remoteHostsString, boolean generateReportDashboard) {
            try {
                // 获取脚本文件
                File f = new File(testFile);
                if (!f.exists() || !f.isFile()) {
                    println("Could not open " + testFile);
                    return;
                }
                // 设置脚本文件
                FileServer.getFileServer().setBaseForScript(f);
    
                HashTree tree = SaveService.loadTree(f);
    
                @SuppressWarnings("deprecation") // Deliberate use of deprecated ctor
                JMeterTreeModel treeModel = new JMeterTreeModel(new Object());// NOSONAR Create non-GUI version to avoid headless problems
                JMeterTreeNode root = (JMeterTreeNode) treeModel.getRoot();
                treeModel.addSubTree(tree, root);
    
                // Hack to resolve ModuleControllers in non GUI mode
                SearchByClass<ReplaceableController> replaceableControllers =
                        new SearchByClass<>(ReplaceableController.class);
                tree.traverse(replaceableControllers);
                Collection<ReplaceableController> replaceableControllersRes = replaceableControllers.getSearchResults();
                for (ReplaceableController replaceableController : replaceableControllersRes) {
                    replaceableController.resolveReplacementSubTree(root);
                }
    
                // Ensure tree is interpreted (ReplaceableControllers are replaced)
                // For GUI runs this is done in Start.java
                // 将测试文件(.jmx文件)解析成HashTree
                HashTree clonedTree = convertSubTree(tree, true);
                
                Summariser summariser = null;
                String summariserName = JMeterUtils.getPropDefault("summariser.name", "");//$NON-NLS-1$
                if (summariserName.length() > 0) {
                    log.info("Creating summariser <{}>", summariserName);
                    println("Creating summariser <" + summariserName + ">");
                    summariser = new Summariser(summariserName);
                }
                ResultCollector resultCollector = null;
                if (logFile != null) {
                    resultCollector = new ResultCollector(summariser);
                    resultCollector.setFilename(logFile);
                    clonedTree.add(clonedTree.getArray()[0], resultCollector);
                }
                else {
                    // only add Summariser if it can not be shared with the ResultCollector
                    if (summariser != null) {
                        clonedTree.add(clonedTree.getArray()[0], summariser);
                    }
                }
    
                if (deleteResultFile) {
                    SearchByClass<ResultCollector> resultListeners = new SearchByClass<>(ResultCollector.class);
                    clonedTree.traverse(resultListeners);
                    Iterator<ResultCollector> irc = resultListeners.getSearchResults().iterator();
                    while (irc.hasNext()) {
                        ResultCollector rc = irc.next();
                        File resultFile = new File(rc.getFilename());
                        if (resultFile.exists() && !resultFile.delete()) {
                            throw new IllegalStateException("Could not delete results file " + resultFile.getAbsolutePath()
                                + "(canRead:"+resultFile.canRead()+", canWrite:"+resultFile.canWrite()+")");
                        }
                    }
                }
                ReportGenerator reportGenerator = null;
                if (logFile != null && generateReportDashboard) {
                    reportGenerator = new ReportGenerator(logFile, resultCollector);
                }
    
                // Used for remote notification of threads start/stop,see BUG 54152
                // Summariser uses this feature to compute correctly number of threads 
                // when NON GUI mode is used
                clonedTree.add(clonedTree.getArray()[0], new RemoteThreadsListenerTestElement());
    
                List<JMeterEngine> engines = new LinkedList<>();
                clonedTree.add(clonedTree.getArray()[0], new ListenToTest(remoteStart && remoteStop ? engines : null, reportGenerator));
                println("Created the tree successfully using "+testFile);
                if (!remoteStart) {
                    // 实例化一个JMeterEngine来对付脚本,JMeterEngine本质就是一个线程
                    JMeterEngine engine = new StandardJMeterEngine();
                    engine.configure(clonedTree);
                    long now=System.currentTimeMillis();
                    println("Starting the test @ "+new Date(now)+" ("+now+")");
                    // 调用runTest方法
                    engine.runTest();
                    engines.add(engine);
                } else {
                    java.util.StringTokenizer st = new java.util.StringTokenizer(remoteHostsString, ",");//$NON-NLS-1$
                    List<String> hosts = new LinkedList<>();
                    while (st.hasMoreElements()) {
                        hosts.add((String) st.nextElement());
                    }
                    
                    DistributedRunner distributedRunner=new DistributedRunner(this.remoteProps);
                    distributedRunner.setStdout(System.out); // NOSONAR
                    distributedRunner.setStdErr(System.err); // NOSONAR
                    distributedRunner.init(hosts, clonedTree);
                    engines.addAll(distributedRunner.getEngines());
                    distributedRunner.start();
                }
                startUdpDdaemon(engines);
            } catch (Exception e) {
                System.out.println("Error in NonGUIDriver " + e.toString());//NOSONAR
                log.error("Error in NonGUIDriver", e);
            }
        }
        

    整体再来梳理下JMeter类逻辑,抛开 GUI 和 Remote test相关的代码,简单说,JMeter 做的事情主要有:

    • 解析命令行参数,加载配置文件;
    • 将 .Jmx 文件解析成 HashTree;
    • 实例化一个StandardJMeterEngine,并把测试的工作交给JMeterEngine;

    当然,JMeter类还有其他重要的职责,比如监听所有的 JMeterEngine ,当接收到 GUI 的 StopTestNow / Shutdown 等命令时候来调用JMeterEngine接口相应的方法。

    接下来看下JMeterEngine,看下这个接口都提供哪些方法?

    /**
     * This interface is implemented by classes that can run JMeter tests.
     */
    public interface JMeterEngine {
        /**
         * Configure engine
         * 配置引擎
         * @param testPlan the test plan
         */
        void configure(HashTree testPlan);
    
        /**
         * Runs the test
         * 执行测试
         * @throws JMeterEngineException if an error occurs
         */
        void runTest() throws JMeterEngineException;
    
        /**
         * Stop test immediately interrupting current samplers
         * 停止测试,立即打断当前samplers
         */
        default void stopTest() {
            stopTest(true);
        }
        /**
         * 停止测试,根据参数是否立即打断当前samplers
         * @param now boolean that tell wether stop is immediate (interrupt) or not (wait for current sample end)
         */
        void stopTest(boolean now);
    
        /**
         * Stop test if running
         * 停止测试运行
         */
        void reset();
    
        /**
         * set Properties on engine
         * 设置引擎属性
         * @param p the properties to set
         */
        void setProperties(Properties p);
    
        /**
         * Exit engine
         * 退出引擎
         */
        void exit();
        
        /**
         * 引擎是否活跃
         * @return boolean Flag to show whether engine is active (true when test is running). Set to false at end of test
         */
        boolean isActive();
    }

    JMeterEngine 依赖于 HashTree,而 HashTree 是由 jmx 文件解析而来,每一个 JMeter 测试计划都会对应一个 jmx 文件。所以我们只要生成合理的 jmx 文件,就可以通过 JMeterEngine 压测引擎去执行测试任务。

    具体 jmx 文件的生成方式,我们可以借鉴JMeter GUI模式下 jmx 文件生成方式。在这里我们的演示的处理方式是,先定义每个组件的生成方式,然后再按一定结构组装各个组件,示意代码如下。

    三、JAVA运行JMeter示例

    遵循以下规则:

    • 将JMeter文件安装在某个地方
    • 在项目lib或者JMeter安装的/ lib/ext文件夹中获取所需的 JMeter jar包。

    JMeter的“压测引擎”就是 StandardJMeterEngine ,我们需要扩展此类或实现自己的JMeterEngine接口。
    示例生成并读取.jmx文件并执行它,代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.zuozewei</groupId>
        <artifactId>jmeter-from-code</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <configuration>
                        <archive>
                            <manifest>
                                <mainClass>com.zuozewei.demo.JMeterFromScratch</mainClass>
                            </manifest>
                        </archive>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.apache.jmeter</groupId>
                <artifactId>ApacheJMeter_java</artifactId>
                <version>4.0</version>
            </dependency>
            <dependency>
                <groupId>org.apache.jmeter</groupId>
                <artifactId>ApacheJMeter_http</artifactId>
                <version>4.0</version>
            </dependency>
        </dependencies>
    
    
    </project>

    测试类

    public class JMeterFromScratch {
    
        public static void main(String[] argv) throws Exception {
            // 设置jmeterHome路径
            String jmeterHome1 = "/Users/apple/Downloads/performance/apache-jmeter-4.0";
            //File jmeterHome = new File(System.getProperty("jmeter.home"));
            File jmeterHome = new File(jmeterHome1);
            String slash = System.getProperty("file.separator");
    
            if (jmeterHome.exists()) {
                File jmeterProperties = new File(jmeterHome.getPath() + slash + "bin" + slash + "jmeter.properties");
                if (jmeterProperties.exists()) {
                    //JMeter Engine 引擎
                    StandardJMeterEngine jmeter = new StandardJMeterEngine();
    
                    //JMeter initialization (properties, log levels, locale, etc)
                    JMeterUtils.setJMeterHome(jmeterHome.getPath());
                    JMeterUtils.loadJMeterProperties(jmeterProperties.getPath());
                    JMeterUtils.initLogging();// you can comment this line out to see extra log messages of i.e. DEBUG level
                    JMeterUtils.initLocale();
    
    
                    // JMeter Test Plan, basically JOrphan HashTree
                    HashTree testPlanTree = new HashTree();
    
                    // 第一个 HTTP Sampler - 打开 baidu.com
                    HTTPSamplerProxy examplecomSampler = new HTTPSamplerProxy();
                    examplecomSampler.setDomain("baidu.com");
                    examplecomSampler.setPort(80);
                    examplecomSampler.setPath("/");
                    examplecomSampler.setMethod("GET");
                    examplecomSampler.setName("Open baidu.com");
                    examplecomSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
                    examplecomSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
    
    
                    // 第二个 HTTP Sampler - 打开 qq.com
                    HTTPSamplerProxy blazemetercomSampler = new HTTPSamplerProxy();
                    blazemetercomSampler.setDomain("qq.com");
                    blazemetercomSampler.setPort(80);
                    blazemetercomSampler.setPath("/");
                    blazemetercomSampler.setMethod("GET");
                    blazemetercomSampler.setName("Open qq.com");
                    blazemetercomSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
                    blazemetercomSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
    
    
                    // Loop Controller 循环控制
                    LoopController loopController = new LoopController();
                    loopController.setLoops(1);
                    loopController.setFirst(true);
                    loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
                    loopController.setProperty(TestElement.GUI_CLASS, LoopControlPanel.class.getName());
                    loopController.initialize();
    
                    // Thread Group 线程组
                    ThreadGroup threadGroup = new ThreadGroup();
                    threadGroup.setName("Example Thread Group");
                    threadGroup.setNumThreads(1);
                    threadGroup.setRampUp(1);
                    threadGroup.setSamplerController(loopController);
                    threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
                    threadGroup.setProperty(TestElement.GUI_CLASS, ThreadGroupGui.class.getName());
    
                    // Test Plan 测试计划
                    TestPlan testPlan = new TestPlan("Create JMeter Script From Java Code");
                    testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
                    testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
                    testPlan.setUserDefinedVariables((Arguments) new ArgumentsPanel().createTestElement());
    
                    // Construct Test Plan from previously initialized elements
                    // 从以上初始化的元素构造测试计划
                    testPlanTree.add(testPlan);
                    HashTree threadGroupHashTree = testPlanTree.add(testPlan, threadGroup);
                    threadGroupHashTree.add(blazemetercomSampler);
                    threadGroupHashTree.add(examplecomSampler);
    
                    // save generated test plan to JMeter's .jmx file format
                    // 将生成的测试计划保存为JMeter的.jmx文件格式
                    SaveService.saveTree(testPlanTree, new FileOutputStream(jmeterHome + slash + "example.jmx"));
    
                    //add Summarizer output to get test progress in stdout like:
                    // 在stdout中添加summary输出,得到测试进度,如:
                    // summary =      2 in   1.3s =    1.5/s Avg:   631 Min:   290 Max:   973 Err:     0 (0.00%)
                    Summariser summer = null;
                    String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");
                    if (summariserName.length() > 0) {
                        summer = new Summariser(summariserName);
                    }
    
    
                    // Store execution results into a .jtl file
                    // 将执行结果存储到.jtl文件中
                    String logFile = jmeterHome + slash + "example.jtl";
                    ResultCollector logger = new ResultCollector(summer);
                    logger.setFilename(logFile);
                    testPlanTree.add(testPlanTree.getArray()[0], logger);
    
                    // Run Test Plan
                    // 执行测试计划
                    jmeter.configure(testPlanTree);
                    jmeter.run();
    
                    System.out.println("Test completed. See " + jmeterHome + slash + "example.jtl file for results");
                    System.out.println("JMeter .jmx script is available at " + jmeterHome + slash + "example.jmx");
                    System.exit(0);
    
                }
            }
    
            System.err.println("jmeter.home property is not set or pointing to incorrect location");
            System.exit(1);
    
    
        }
    }

    测试结果

    summary =      2 in 00:00:03 =    0.8/s Avg:   951 Min:   933 Max:   969 Err:     0 (0.00%)
    Test completed. See /Users/apple/Downloads/performance/apache-jmeter-4.0/example.jtl file for results
    JMeter .jmx script is available at /Users/apple/Downloads/performance/apache-jmeter-4.0/example.jmx
    
    Process finished with exit code 0

    本文源码地址:
    https://github.com/zuozewei/JMeter-Examples
    ---------------------
    作者:zuozewei
    来源:CSDN
    原文:https://blog.csdn.net/zuozewei/article/details/85042829
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    RE
    【LeetCode】198. House Robber
    【LeetCode】053. Maximum Subarray
    【LeetCode】152. Maximum Product Subarray
    【LeetCode】238.Product of Array Except Self
    【LeetCode】042 Trapping Rain Water
    【LeetCode】011 Container With Most Water
    【LeetCode】004. Median of Two Sorted Arrays
    【LeetCode】454 4Sum II
    【LeetCode】259 3Sum Smaller
  • 原文地址:https://www.cnblogs.com/yigui/p/11072935.html
Copyright © 2020-2023  润新知