zoukankan      html  css  js  c++  java
  • 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
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    qt setfixedsize以后怎么让窗口可正常resize
    总线操作使用工具
    DTK 获取活动色
    qt 设置背景色
    python_itchat模块登陆问题
    python_基础知识
    python_爬虫_str类型的html文本去标签
    工作__问题
    服务器_sshfs的安装、挂载、取消挂载
    python_爬虫_通过selenium获取人人网cookie值并模拟登陆个人界面
  • 原文地址:https://www.cnblogs.com/yigui/p/11072935.html
Copyright © 2011-2022 走看看