jmeter源码---StandardJMeterEngine

33 篇文章 3 订阅
31 篇文章 6 订阅

概述

执行jmter tests ,直接用于本地GUI和非GUI调用,或者在服务器模式下运行时由RemoteJMeterEngineImpl启动

介绍

在JMeterEngineImpl中做了一部分的解释,可以结合着看

主要变量

灵魂级变量,注意关键字volatile

private static volatile StandardJMeterEngine engine;

构造函数

有两种构造函数,带参和不带参

public StandardJMeterEngine() {
    this(null);
}

public StandardJMeterEngine(String host) {
    this.host = host;
    // Hack to allow external control
    initSingletonEngine(this);
}

操作engine

initSingletonEngine()、initSingletonEngine()、stopEngineNow()、stopEngine()略

stopThread

根据threadName停止线程的执行:分两种情况立即停止和非立即停止,根据第二个参数的值决定

private static boolean stopThread(String threadName, boolean now) {
    if (engine == null) {
        return false;// e.g. not yet started
    }
    boolean wasStopped = false;
    // ConcurrentHashMap does not need synch. here
    for (AbstractThreadGroup threadGroup : engine.groups) {
        wasStopped = wasStopped || threadGroup.stopThread(threadName, now);
    }
    return wasStopped;
}

ThreadGroup.stopThread及调用及具体实现参考代码如下

public boolean stopThread(String threadName, boolean now) {
       for(Entry<JMeterThread, Thread> entry : allThreads.entrySet()) {
           JMeterThread thrd = entry.getKey();
           if (thrd.getThreadName().equals(threadName)) {
               stopThread(thrd, entry.getValue(), now);
               return true;
           }
       }
       return false;
   }
    /**
    * Hard Stop JMeterThread thrd and interrupt JVM Thread if interrupt is true
    * @param jmeterThread {@link JMeterThread}
    * @param jvmThread {@link Thread}
    * @param interrupt Interrupt thread or not
    */
   private void stopThread(JMeterThread jmeterThread, Thread jvmThread, boolean interrupt) {
       jmeterThread.stop();
       jmeterThread.interrupt(); // interrupt sampler if possible
       if (interrupt && jvmThread != null) { // Bug 49734
           jvmThread.interrupt(); // also interrupt JVM thread
       }
   }

configure

参考 http://blog.csdn.net/yue530tomtom/article/details/78016823#t2

runTest

参考 http://blog.csdn.net/yue530tomtom/article/details/78016823#t3

removeThreadGroups

移除线程组,在run方法里调用

private void removeThreadGroups(List<?> elements) {
    Iterator<?> iter = elements.iterator();
    while (iter.hasNext()) { // Can't use for loop here because we remove elements
        Object item = iter.next();
        if (item instanceof AbstractThreadGroup) {
            iter.remove();
        } else if (!(item instanceof TestElement)) {
            iter.remove();
        }
    }
}

notifyTestListenersOfStart

测试开始通知监听

private void notifyTestListenersOfStart(SearchByClass<TestStateListener> testListeners) {
    for (TestStateListener tl : testListeners.getSearchResults()) {
        if (tl instanceof TestBean) {
            TestBeanHelper.prepare((TestElement) tl);
        }
        if (host == null) {
            tl.testStarted();
        } else {
            tl.testStarted(host);
        }
    }
}

介绍本方法需要了解下TestStateListener

public interface TestStateListener {                                                                        
    void testStarted();
    void testStarted(String host);
    void testEnded();
    void testEnded(String host);
}  

testStarted:在测试开始之前调用
testEnded:在所有线程测试结束时调用一次

notifyTestListenersOfEnd

测试结束通知监听

private void notifyTestListenersOfEnd(SearchByClass<TestStateListener> testListeners) {
    log.info("Notifying test listeners of end of test");
    for (TestStateListener tl : testListeners.getSearchResults()) {
        try {
            if (host == null) {
                tl.testEnded();
            } else {
                tl.testEnded(host);
            }
        } catch (Exception e) {
            log.warn("Error encountered during shutdown of " + tl.toString(), e);
        }
    }
    if (host != null) {
        log.info("Test has ended on host " + host);
        long now = System.currentTimeMillis();
        System.out.println("Finished the test on host " + host + " @ " + new Date(now) + " (" + now + ")" // NOSONAR Intentional
                + (EXIT_AFTER_TEST ? " - exit requested." : ""));
        if (EXIT_AFTER_TEST) {
            exit();
        }
    }
    active = false;
}

stopTest

参考 http://blog.csdn.net/yue530tomtom/article/details/78016823#t5

StopTest

实现runnable接口,主要操作AbstractThreadGroup中的方法

run()

  • JMeterContextService清零:JMeterContextService.startTest()
public static synchronized void startTest() {
    if (testStart == 0) {
        numberOfActiveThreads = 0;
        testStart = System.currentTimeMillis();
        JMeterUtils.setProperty("TESTSTART.MS",Long.toString(testStart));
    }
}
public static synchronized void clearTotalThreads() {
    totalThreads = 0;
    numberOfThreadsStarted = 0;
    numberOfThreadsFinished = 0;
}
  • PreCompiler the Tashree
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", e);
    return; // no point continuing
}
  • 利用SearchByClass解析所有TestStateListener 加入到testList中
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);
  • 触发上一步中解析的testListener的testStarted方法:ResultCollector会递增instanceCount,初始化fileOutput;TestPlan会设置FileServer的basedir,添加classpath; JavaSampler会初始化真正要跑的AbstractJavaSamplerClient类;
  • 利用SearchByClass解析所有ThreadGroup(包括SetupThreadGroup,ThreadGroup, PostThreadGroup)
notifyTestListenersOfStart(testListeners);

private void notifyTestListenersOfStart(SearchByClass<TestStateListener> testListeners) {
    for (TestStateListener tl : testListeners.getSearchResults()) {
        if (tl instanceof TestBean) {
            TestBeanHelper.prepare((TestElement) tl);
        }
        if (host == null) {
            tl.testStarted();
        } else {
            tl.testStarted(host);
        }
    }
}
  • 实例化一个ListenerNotifier实例,用来通知事件发生
ListenerNotifier notifier = new ListenerNotifier();
  • 启动所有SetupThreadGroup(一般情况下没有SetupThreadGroup)并等待到都结束
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);
        startThreadGroup(group, groupCount, setupSearcher, testLevelElements, notifier);
        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();
}
  • 进行一次gc后 开始跑真正的测试,即启动所有的ThreadGroup,这里会检查serialized属性,用来判断是否这些ThreadGroup串行执行
JMeterUtils.helpGC();
  • 等待所有的ThreadGroup结束
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 || 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();
  • 若有 PostThreadGroup(一般没有),执行所有的PostThreadGroup并等待至所有PostThreadGroup结束
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
}
  • 触发第三步中解析的testListener的testEnded方法:JavaSampler会调用真正跑的AbstractJavaSamplerClient的teardownTest方法,可以打印该JavaSamplerClient测试总共花费的时间;ResultCollector用来将测试结果写如文件生成;reportTestPlan用来关闭文件。
notifyTestListenersOfEnd(testListeners);
JMeterContextService.endTest();

startThreadGroup

启动线程组,run方法中调用

private void startThreadGroup(AbstractThreadGroup group, int groupCount, SearchByClass<?> searcher,
        List<?> testLevelElements, ListenerNotifier notifier) {
    try {
        int numThreads = group.getNumThreads();
        JMeterContextService.addTotalThreads(numThreads);
        boolean onErrorStopTest = group.getOnErrorStopTest();
        boolean onErrorStopTestNow = group.getOnErrorStopTestNow();
        boolean onErrorStopThread = group.getOnErrorStopThread();
        boolean onErrorStartNextLoop = group.getOnErrorStartNextLoop();
        String groupName = group.getName();
        log.info("Starting " + numThreads + " threads for group " + groupName + ".");

        if (onErrorStopTest) {
            log.info("Test will stop on error");
        } else if (onErrorStopTestNow) {
            log.info("Test will stop abruptly on error");
        } else if (onErrorStopThread) {
            log.info("Thread will stop on error");
        } else if (onErrorStartNextLoop) {
            log.info("Thread will start next loop on error");
        } else {
            log.info("Thread will continue on error");
        }
        ListedHashTree threadGroupTree = (ListedHashTree) searcher.getSubTree(group);
        threadGroupTree.add(group, testLevelElements);

        groups.add(group);
        group.start(groupCount, notifier, threadGroupTree, this);
    } catch (JMeterStopTestException ex) { // NOSONAR Reported by log
        JMeterUtils.reportErrorToUser("Error occurred starting thread group :" + group.getName()
                + ", error message:" + ex.getMessage() + ", \r\nsee log file for more details", ex);
        return; // no point continuing
    }
}

waitThreadsStopped

等待线程停止,run方法中调用

/**
 * Wait for Group Threads to stop
 */
private void waitThreadsStopped() {
    // ConcurrentHashMap does not need synch. here
    for (AbstractThreadGroup threadGroup : groups) {
        threadGroup.waitThreadsStopped();
    }
}
/**
 * Wait for all Group Threads to stop
 */
@Override
public void waitThreadsStopped() {
    if (delayedStartup) {
        waitThreadStopped(threadStarter);
    }
    for (Thread t : allThreads.values()) {
        waitThreadStopped(t);
    }
}

/**
 * Wait for thread to stop
 * @param thread Thread
 */
private void waitThreadStopped(Thread thread) {
    if (thread != null) {
        while (thread.isAlive()) {
            try {
                thread.join(WAIT_TO_DIE);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

学习备忘

原文连接 http://blog.csdn.net/yue530tomtom/article/details/78055365

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值