JMeterEngine接口比较简单,总共7个方法,但是没javadoc,所以光看接口的话只能凭方法名猜测了。我们这里简要分析下:
1. configure(HashTree testPlan)
前面博文已经说过HashTree是JMeter跑测试依赖的数据结构,也提到过HashTree的结构一般是TestPlan-->ThreadGroup-->Sampler-->ResultCollector,这个方法就是在跑测试之前配置下这些测试数据了。参考StandardJMeterEngine,从HashTree中解析出TestPlan, 获取TestPlan的serialized和tearDownOnShutdown并保存为local属性,同时把整个HashTree也保存到local。
(Note: 解释下关于上面两个保存到local的属性,StandardJMeterEngine依赖线程组ThreadGroup, 一个测试中可能会有多个线程组,如果serialized为true,则StandardJMeterEngine会串行的去跑这些线程组,每启动一个ThreadGroup主线程都会等它结束;否则就并行跑所有的线程组。而tearDownOnShutdown是和PostThreadGroup配合使用的,这个Special Thread Group专门用来做清理工作,参考该类的javadoc):
/** * PostThreadGroup is a special type of ThreadGroup that can be used for * performing actions at the end of a test for cleanup and such. */
如果在HashTree配置中有PostThreadGroup,那么在主线程组(ThreadGroup)跑完之后,StandardJMeterEngine会去check这个tearDownOnShutdown属性,若该属性值true就启动PostThreadGroup。
2. runTest()
调用该方法用来跑测试。还是参考StandardJMeterEngine的实现,很简单,作为Runnable,启动一个线程并触发它的run()方法,若报异常则调下stopTest(),抛出JMeterEngineException。至于真正跑测试的过程run()方法,放到后面分析StandardJMeterEngine部分.
3. stopTest(boolean now)
停止测试,若now为true则停止动作立即执行;若为false则停止动作缓刑,它会等待当前正在跑的测试至少跑完一个iteration。
4. reset()
重置。在StandardJMeterEngine中就是直接调用stopTest(true).
5. setProperties(Properties p)
设置属性,可以将额外的配置文件通过该方法添加进去。它会保存在JMeterUtils中,该类保存了JMeterEngine runtime所需要的所有配置参数,在前面博文有分析过。
6. exit()
是为Remote Test准备的,如果当前的测试是从一个客户端的JMeter跑远程JMeterEngine的remote samples,则应该调用该exit()方法来关闭远程的测试.
7. boolean isActive()
是否该JMeterEngine是active状态,在confgiure()的时候设该值为true,在跑完测试(指的是该JMeterEngine所有ThreadGroup)之后设置为false。言下之意是,如果active==true,则说明该JMeterEngine已经配置完测试并且还没跑完,我们不能再进行configure或者runTest了;若active == false, 则该JMeterEngine是空闲的,我们可以重新配置HashTree,跑新的测试.
很简单吧,相信看到这里,已经很容易coding进行代码驱动JMeter了。下面再简要分析下JMeterEngine的标准实现StandardJMeterEngine,先给个类图作为整体认识:
简要解读:HashTree是依赖的数据结构;SearchByClass用来查找HashTree中的所有节点,并把节点实例化为真正的对象,例如图中TestPlan/ThreadGroup/JavaSampler/ResultCollector在HashTree中本来都是只是配置,全部通过SearchByClass实例化的;实例化出来的对象如果是TestStateListener类型,则会在有生命周期的函数回调,测试前调testStarted,结束掉testEnded, 比如ResultCollector是该类型的一种,在结束的时候回调testEnded方法完成report的写入;PreCompiler用来解析Arguments, 把TestPlan节点中配置的参数作为JMeterVariables加入到测试线程上线文中;ThreadGroup用来用来管理一组线程,包括线程的个数/启动/关闭等;StopTest作为其内部类对外不可见,作为一个Runnable,作用是异步停止测试,前面分析JMeterEngine接口时提到的stopTest方法也是通过该内部类实现的。
现在可以分析跑测试的流程了,StandardJMeterEngine.run()方法:
1) JMeterContextService清零:numberOfActiveThreads=0, 重置testStart时间
2) PreCompiler the Tashree,作用见“简要解读”
3) 利用SearchByClass解析所有TestStateListener 加入到testList中
4) 触发 3) 中解析的testListener的testStarted方法:ResultCollector会递增instanceCount,初始化fileOutput;TestPlan会设置FileServer的basedir,添加classpath; JavaSampler会初始化真正要跑的AbstractJavaSamplerClient类;
5) 利用SearchByClass解析所有ThreadGroup(包括SetupThreadGroup,ThreadGroup, PostThreadGroup)
6) 实例化一个ListenerNotifier实例,用来通知事件发生
7) 启动所有SetupThreadGroup(一般情况下没有SetupThreadGroup)并等待到都结束
8) 进行一次gc后 开始跑真正的测试,即启动所有的ThreadGroup,这里会检查serialized属性,用来判断是否这些ThreadGroup串行执行
9) block here, 等待所有的ThreadGroup结束
10)若有 PostThreadGroup(一般没有),执行所有的PostThreadGroup并等待至所有PostThreadGroup结束
12) 触发 3)中解析的testListener的testEnded方法:JavaSampler会调用真正跑的AbstractJavaSamplerClient的teardownTest方法,可以打印该JavaSamplerClient测试总共花费的时间;ResultCollector用来将测试结果写如文件生成;reportTestPlan用来关闭文件。