zoukankan      html  css  js  c++  java
  • Jmeter源码框架

    首先jmeter框架入口类: NewDriver类(src/core/org/apache/jmeter/NewDriver.java)

    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.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类的star方法,jmeter类:

    Main JMeter class; processes options and starts the GUI, non-GUI or server as appropriate.

    可以看出start函数主要用于根据命令行命令执行不同的操作

    public void start(String[] args) {  
            //获得I/O的通道管理器  
           if(NioClient.getClientInstance().init(Constraint.IP,Constraint.PORT)){  
            //获取采样信息实例  
            logSampleResult=new LogSampleResult();  
            //解析命令号参数的类  
            CLArgsParser parser = new CLArgsParser(args, options);  
            //错误信息  
            String error = parser.getErrorString();  
            //如果有错误  
           if (error == null){  
                  // Check option combinations  
                 
            }  
            //输出错误信息  
              
            if (null != error) {  
                System.err.println("Error: " + error);  
                System.out.println("Usage");  
                System.out.println(CLUtil.describeOptions(options).toString());  
                // repeat the error so no need to scroll back past the usage to see it  
                System.out.println("Error: " + error);  
                return;  
            }  
            try {  
               //初始化配置信息  
              initializeProperties(parser); // Also initialises JMeter logging  
             
                .....;  
      
              
                //// Update classloader if necessary   
                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  
                // TODO perhaps should share code with __time() function for this...  
                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$  
      
      
                <span style="color:#FF0000;">/** 
                 *开始真正有用的了 
                 */</span>  
               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"));// $NON-NLS-1$  
                } else if (parser.getArgumentById(OPTIONS_OPT) != null) {  
                    displayAsciiArt();  
                    System.out.println(CLUtil.describeOptions(options).toString());  
                } else if (parser.getArgumentById(SERVER_OPT) != null) {  
                    // Start the server  
                    try {  
                        RemoteJMeterEngineImpl.startServer(JMeterUtils.getPropDefault("server_port", 0)); // $NON-NLS-1$  
                    } catch (Exception ex) {  
                        System.err.println("Server failed to start: "+ex);  
                        log.error("Giving up, as server failed with:", ex);  
                        throw ex;  
                    }  
                    startOptionalServers();  
                } else {  
                    String testFile=null;  
                    String engineFilePath=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 engineFileOpt = parser.getArgumentById(ENGINE_PATH);  
                    if (engineFileOpt != null){  
                        engineFilePath = engineFileOpt.getArgument();  
                        
                    }  
                    CLOption testReportOpt = parser.getArgumentById(REPORT_GENERATING_OPT);  
                    if (testReportOpt != null) { // generate report from existing file  
                        String reportFile = testReportOpt.getArgument();  
                        extractAndSetReportOutputFolder(parser);  
                        ReportGenerator generator = new ReportGenerator(reportFile, null);  
                        generator.generate();  
                    } else if (parser.getArgumentById(NONGUI_OPT) == null) { // not non-GUI => GUI  
                        //在有用户界面下执行  
                       <span style="color:#FF0000;"><span style="background-color: rgb(255, 255, 255);"> startGui(testFile,parser);</span></span>  
                        startOptionalServers();  
                      
                    } else { // NON-GUI must be true  
                        extractAndSetReportOutputFolder(parser);  
                          
                        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) {  
                            if(jtlFile == null) {  
                                throw new IllegalUserActionException(  
                                    "Option -"+ ((char)REPORT_AT_END_OPT)+" requires -"+((char)LOGFILE_OPT )+ " option");  
                            }  
                        }  
                        ///无用户界面执行  
                       <span style="color:#FF0000;">startNonGui(testFile,engineFilePath, jtlFile, rem, reportAtEndOpt != null);</span>  
                        startOptionalServers();  
                    }  
                }  
            } catch (IllegalUserActionException e) {  
                System.out.println("Incorrect Usage:"+e.getMessage());  
                System.out.println(CLUtil.describeOptions(options).toString());  
            } catch (Throwable e) {  
                log.fatalError("An error occurred: ",e);  
                System.out.println("An error occurred: " + e.getMessage());  
                System.exit(1); // TODO - could this be return?  
            }  
        }  

    上述代码主要功能函数为startgui和startnongui,其中startgui:

    private void startGui(String testFile,CLArgsParser parser) {  
            CLOption weizhiOpt = parser.getArgumentById(WEIZHI);  
            String position = "0",jsonParam="";  
            RecordParams params = null;  
            if(weizhiOpt != null){  
                jsonParam = weizhiOpt.getArgument();  
                params = JSON.parseObject(jsonParam,RecordParams.class);  
                position = params.getLocation();  
                if(position==null||position==""){  
                    position = "0";  
                }  
                if("setup".equalsIgnoreCase(position)){  
                    position = "0";  
                }  
                if("event".equalsIgnoreCase(position)){  
                    position = "1";  
                }  
                if("teardown".equalsIgnoreCase(position)){  
                    position = "2";  
                }  
            }  
            /////////////////////////////////////////  
            String jMeterLaf = LookAndFeelCommand.getJMeterLaf();  
            try {  
                UIManager.setLookAndFeel(jMeterLaf);  
            } catch (Exception ex) {  
                log.warn("Could not set LAF to:"+jMeterLaf, ex);  
            }  
      
            PluginManager.install(this, true);  
      
            JMeterTreeModel treeModel = new JMeterTreeModel();  
            JMeterTreeListener treeLis = new JMeterTreeListener(treeModel);  
            final ActionRouter instance = ActionRouter.getInstance();  
            instance.populateCommandMap();  
            treeLis.setActionHandler(instance);  
            GuiPackage guiPack = GuiPackage.getInstance(treeLis, treeModel);  
            guiPack.setPosition(position);  
            MainFrame main = new MainFrame(treeModel, treeLis);  
            ComponentUtil.centerComponentInWindow(main, 80);  
            boolean visible = JMeterUtils.getProperty("jmeter.visible").equals("true")?true:false;  
            if(visible){  
                main.setVisible(true);//TODO 设置可见性,可见true  
            }else{  
                main.setVisible(false);//TODO 设置可见性,不可见false  
            }  
            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);  
            }  
            // TODO 启动录制  
            JMeterTreeModel jMeterTreeModel = GuiPackage.getInstance().getTreeModel();  
            List<JMeterTreeNode> jmt = jMeterTreeModel.getNodesOfType(ProxyControl.class);  
            ProxyControlGui httpgui = (ProxyControlGui) GuiPackage.getInstance().getGui(jmt.get(0).getTestElement());  
            httpgui.startProxy();  
            // TODO 在这里打开浏览器  
            if(params.getBrowser()!=null){  
                // TODO 打开浏览器,在这之前应该设置代理,这里需要手动去设置  
                String url = params.getUrl();  
                try {  
                    BrowserUtil.browse(url);  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  
            // TODO 启动录制控制器   
            try {  
                new RecordBrowser("录制控制器",position);  
            } catch (HeadlessException e) {  
                e.printStackTrace();  
            } catch (ClassNotFoundException e) {  
                e.printStackTrace();  
            } catch (InstantiationException e) {  
                e.printStackTrace();  
            } catch (IllegalAccessException e) {  
                e.printStackTrace();  
            } catch (UnsupportedLookAndFeelException e) {  
                e.printStackTrace();  
            }   
        } 

    startnongui

    private void startNonGui(String testFile,String engineFilePath, 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  
              
      
            ... ...  
      
      
          //设置场景  
         configureScene(testFile,engineFilePath,logFile,driver,remoteStart,remoteHostsString,generateReportDashboard);  
        }  

    进入configurescene

    private void configureScene(String testFile,String engineFilePath,String logFile,JMeter driver,CLOption remoteStart,String remoteHostsString,boolean generateReportDashboard){  
              try {  
                runController=new RunController();  
                Scence scene=Utils.loadScence(testFile);  
                //COUNT_SCRIPT=scene.getScripts().getScript().size();  
                log.info("Script size "+COUNT_SCRIPT);    
                for(Script script  : scene.getScripts().getScript()){  
                if(script.getRunflag().equals("1"))  
                {  
                    COUNT_SCRIPT++;  
                            //执行runnongui  
                           driver.runNonGui(engineFilePath+script.getPath(),logFile , remoteStart != null, remoteHostsString, generateReportDashboard,scene,script,runController);  
                }  
                }  
            } catch (FileNotFoundException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
                logSampleResult.logError("文件"+testFile+"不存在");  
            } catch (JAXBException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
                logSampleResult.logError("文件"+testFile+"格式损坏,解析失败。");  
            }  
        }  

    runnongui:这个类滴代码是相当多啊,主要是跑脚本

    private void runNonGui(String testFile, String logFile, boolean remoteStart, String remote_hosts_string, boolean generateReportDashboard,Scence scene,Script script,RunController runController) {  
            try {  
                //首先获得脚本文件  
               File f = new File(testFile);  
                if (!f.exists() || !f.isFile()) {  
                    println("Could not open " + testFile);  
                    logSampleResult.logError("文件"+testFile+"不存在");  
                    System.exit(0);  
                }  
                  
                // TODO 设置脚本文件  
                FileServer.getFileServer().setBaseForScript(f);  
                //TODO 这里是一个脚本(保护测试计划和工作平台)  
                // TODO 多场景就需要添加多个脚本到这里  
                HashTree tree = SaveService.loadTree(f);  
      
                @SuppressWarnings("deprecation") // Deliberate use of deprecated ctor  
                JMeterTreeModel treeModel = new JMeterTreeModel(new Object());// 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);  
                }  
      
                // Remove the disabled items  
                // For GUI runs this is done in Start.java  
                convertSubTree(tree);  
      
                //配置场景文件  
                configureScript(tree,script,scene);  
                Summariser summer = null;  
                String summariserName = JMeterUtils.getPropDefault("summariser.name", "");//$NON-NLS-1$  
                if (summariserName.length() > 0) {  
                    log.info("Creating summariser <" + summariserName + ">");  
                    println("Creating summariser <" + summariserName + ">");  
                    summer = new Summariser(summariserName);  
                }  
                ReportGenerator reportGenerator = null;  
                if (logFile != null) {  
                    ResultCollector logger = new ResultCollector(summer);  
                    logger.setFilename(logFile);  
                    tree.add(tree.getArray()[0], logger);  
                    if(generateReportDashboard) {  
                        reportGenerator = new ReportGenerator(logFile, logger);  
                    }  
                }  
                else {  
                    // only add Summariser if it can not be shared with the ResultCollector  
                    if (summer != null) {  
                        tree.add(tree.getArray()[0], summer);  
                    }  
                }  
                // 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  
                tree.add(tree.getArray()[0], new RemoteThreadsListenerTestElement());  
      
                
                tree.add(tree.getArray()[0], new ListenToTest(parent, (remoteStart && remoteStop) ? engines : null, reportGenerator));  
                println("Created the tree successfully using "+testFile);  
                if (!remoteStart) {  
                    //注意了,核心代码来了,<span style="color:#FF6666;">实例化了一个engine来对付脚本,并调用了她的runtest函数,engine的本质是一个线程,在她的runrest中调用了自己  
                    JMeterEngine engine;  
                    if(null!=scene&&null!=script)  
                    engine= new StandardJMeterEngine(script.getName(),scene.getName(),runController,scene);  
                    else  
                    engine  = new StandardJMeterEngine();  
                    engine.configure(tree);  
                    long now=System.currentTimeMillis();  
                    println("Starting the test @ "+new Date(now)+" ("+now+")");  
                    engine.runTest();  
                    engines.add(engine);</span>  
                   
                } else {  
                    java.util.StringTokenizer st = new java.util.StringTokenizer(remote_hosts_string, ",");//$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);  
                    distributedRunner.setStdErr(System.err);  
                    distributedRunner.init(hosts, tree);  
                    engines.addAll(distributedRunner.getEngines());  
                    distributedRunner.start();  
                }  
                startUdpDdaemon(engines);  
               
            } catch (Exception e) {  
                System.out.println("Error in NonGUIDriver " + e.toString());  
                log.error("Error in NonGUIDriver", e);  
            }  
        }  

    好了,完了的jmeter类过去的,迎面走来的是更可恶的standardjmeterengine类

    删掉冗余,只留核心:

    public void run() {  
            log.info("Running the test!");  
            running = true;  
      
            /*  
             * Ensure that the sample variables are correctly initialised for each run.  
             * TODO is this the best way to do this? should it be done elsewhere ?  
             */  
            SampleEvent.initSampleVariables();  
      
            JMeterContextService.startTest();  
            try {  
                PreCompiler compiler = new PreCompiler();  
                test.traverse(compiler);  
            } catch (RuntimeException e) {  
                log.error("Error occurred compiling the tree:",e);  
                JMeterUtils.reportErrorToUser("Error occurred compiling the tree: - see log file");  
                return; // no point continuing  
            }  
            /**  
             * Notification of test listeners needs to happen after function  
             * replacement, but before setting RunningVersion to true.  
             */  
            SearchByClass<TestStateListener> testListeners = new SearchByClass<>(TestStateListener.class); // TL - S&E  
            test.traverse(testListeners);  
      
            // Merge in any additional test listeners  
            // currently only used by the function parser  
            testListeners.getSearchResults().addAll(testList);  
            testList.clear(); // no longer needed  
      
            test.traverse(new TurnElementsOn());  
            notifyTestListenersOfStart(testListeners);  
      
            List<?> testLevelElements = new LinkedList<>(test.list(test.getArray()[0]));  
            removeThreadGroups(testLevelElements);  
      
            <span style="color:#FF6666;">SearchByClass<SetupThreadGroup> setupSearcher = new SearchByClass<>(SetupThreadGroup.class);  
            SearchByClass<AbstractThreadGroup> searcher = new SearchByClass<>(AbstractThreadGroup.class);  
            SearchByClass<PostThreadGroup> postSearcher = new SearchByClass<>(PostThreadGroup.class);  
      
            test.traverse(setupSearcher);  
            test.traverse(searcher);  
            test.traverse(postSearcher);</span>  
              
            TestCompiler.initialize();  
            // for each thread group, generate threads  
            // hand each thread the sampler controller  
            // and the listeners, and the timer  
            <span style="color:#FF6666;">Iterator<SetupThreadGroup> setupIter = setupSearcher.getSearchResults().iterator();  
            Iterator<AbstractThreadGroup> iter = searcher.getSearchResults().iterator();  
            Iterator<PostThreadGroup> postIter = postSearcher.getSearchResults().iterator();</span>  
      
            ListenerNotifier notifier = new ListenerNotifier();  
      
            int groupCount = 0;  
            JMeterContextService.clearTotalThreads();  
            //遍历  
           <span style="color:#FF6666;"> if (setupIter.hasNext()) {  
                log.info("Starting setUp thread groups");  
                while (running && setupIter.hasNext()) {//for each setup thread group  
                    AbstractThreadGroup group = setupIter.next();  
                    groupCount++;  
                    String groupName = group.getName();  
                    log.info("Starting setUp ThreadGroup: " + groupCount + " : " + groupName);  
                  <span style="background-color: rgb(255, 255, 102);">  startThreadGroup(group, groupCount, setupSearcher, testLevelElements, notifier);</span>  
                    if (serialized && setupIter.hasNext()) {  
                        log.info("Waiting for setup thread group: "+groupName+" to finish before starting next setup group");  
                        group.waitThreadsStopped();  
                    }  
                }      
                log.info("Waiting for all setup thread groups to exit");  
                //wait for all Setup Threads To Exit  
                waitThreadsStopped();  
                log.info("All Setup Threads have ended");  
                groupCount=0;  
                JMeterContextService.clearTotalThreads();  
            }  
    </span>  
            groups.clear(); // The groups have all completed now                  
      
            /*  
             * Here's where the test really starts. Run a Full GC now: it's no harm  
             * at all (just delays test start by a tiny amount) and hitting one too  
             * early in the test can impair results for short tests.  
             */  
            JMeterUtils.helpGC();  
              
            JMeterContextService.getContext().setSamplingStarted(true);  
            boolean mainGroups = running; // still running at this point, i.e. setUp was not cancelled  
            while (running && iter.hasNext()) {// for each thread group  
                AbstractThreadGroup group = iter.next();  
                //ignore Setup and Post here.  We could have filtered the searcher. but then  
                //future Thread Group objects wouldn't execute.  
                if (group instanceof SetupThreadGroup) {  
                    continue;  
                }  
                if (group instanceof PostThreadGroup) {  
                    continue;  
                }  
                groupCount++;  
                String groupName = group.getName();  
                log.info("Starting ThreadGroup: " + groupCount + " : " + groupName);  
                startThreadGroup(group, groupCount, searcher, testLevelElements, notifier);  
                if (serialized && iter.hasNext()) {  
                    log.info("Waiting for thread group: "+groupName+" to finish before starting next group");  
                    group.waitThreadsStopped();  
                }  
            } // end of thread groups  
            if (groupCount == 0){ // No TGs found  
                log.info("No enabled thread groups found");  
            } else {  
                if (running) {  
                    log.info("All thread groups have been started");  
                } else {  
                    log.info("Test stopped - no more thread groups will be started");  
                }  
            }  
      
            //wait for all Test Threads To Exit  
            waitThreadsStopped();  
            groups.clear(); // The groups have all completed now              
      
            if (postIter.hasNext()){  
                groupCount = 0;  
                JMeterContextService.clearTotalThreads();  
                log.info("Starting tearDown thread groups");  
                if (mainGroups && !running) { // i.e. shutdown/stopped during main thread groups  
                    running = shutdown & tearDownOnShutdown; // re-enable for tearDown if necessary  
                }  
                while (running && postIter.hasNext()) {//for each setup thread group  
                    AbstractThreadGroup group = postIter.next();  
                    groupCount++;  
                    String groupName = group.getName();  
                    log.info("Starting tearDown ThreadGroup: " + groupCount + " : " + groupName);  
                    startThreadGroup(group, groupCount, postSearcher, testLevelElements, notifier);  
                    if (serialized && postIter.hasNext()) {  
                        log.info("Waiting for post thread group: "+groupName+" to finish before starting next post group");  
                        group.waitThreadsStopped();  
                    }  
                }  
                waitThreadsStopped(); // wait for Post threads to stop  
            }  
      
            notifyTestListenersOfEnd(testListeners);  
            JMeterContextService.endTest();  
            if (JMeter.isNonGUI() && SYSTEM_EXIT_FORCED) {  
                log.info("Forced JVM shutdown requested at end of test");  
                System.exit(0);  
            }  
        }  

     [转自:http://blog.csdn.net/asde1239/article/details/52766058]

  • 相关阅读:
    winrt组件库(包括翻书组件)
    WebRequest 获取网页乱码
    OpenNI结合Unity3D Kinect进行体感游戏开发(转)
    python(pyqt)开发环境搭建
    win8开发wpf程序遇到的无语问题
    winrt 页面进入动画
    winrt 根据类型生成实例
    性能测试基础
    性能基础入门篇
    项目部署
  • 原文地址:https://www.cnblogs.com/yigui/p/8431154.html
Copyright © 2011-2022 走看看