JMeter 源码解读 [5] - 核心类 org.apache.jmeter.JMeter
上一篇 程序入口 NewDriver 提到Main
函数是通过反射的方式调用org.apache.jmeter.JMeter
的 start
函数来启动Jmeter ,那么今天我们来看看Jmeter
这个类是怎么工作的.
我们从start
函数来开始分析,由于外层的NewDriver
可以看做一层透明的代理,实际的业务逻辑是透传到JMeter
来处理的,首先就是解析启动时候传入的外部命令行参数
1 | CLArgsParser parser = new CLArgsParser(args, options); |
我们看到上面的代码的主要工作是解析命令行参数,并且判断有没有存在矛盾的组合,例如GUI 相关的参数,但是实际的运行模式是非GUI 模式等。
各种相关解析的任务完成后,有一个比较重要的工作updateClossLoader
的调用,它是JMeter
类自身的一个方法,我们可以来看一下
1 | private void updateClassLoader() throws MalformedURLException { |
它的实际作用是把search_paths
和user.classpath
里面设置的 jar 文件添加到自定义的classloader 中,它的作用可以让我们在某些场景下更方便使用JMeter,例如我们自定义的Java Sampler
,在官方的guide里说是要把Java Sampler 打包成 Jar 放到lib/ext
目录下,这个很麻烦,实际上我们可以通过设置search_paths
和user.classpath
的方式来简化操作。
然后我们再往下看,跳过一些处理特定option
的code ,最核心的就是如下两个核心调用,一个是启动 GUI 的模式, 这里传入的testFile
参数就是我们的 jmx
测试 plan 文件路径
1 | startGui(testFile); |
另外一种就是非 GUI 模式
1 | startNonGui(testFile, jtlFile, rem, reportAtEndOpt != null); |
startOptionalServers()
是一个独立的BeanShell
server, 用来方便对 Jmeter
进程做一些动态调整,以后可以单独写一个来介绍beanshell server
相关的东西, 这里先不关注了。GUI 的模式在启动过后就能看到界面了(一个 swing 的 app)等待用户的输入,所以我们先看一下startNonGui
这个方法, 这个方法的核心是创建了一个新的JMeter
driver (源码里自己也有一个疑问,why does it create a new instance?) ,在非分布式的场景下,实际最后是调用了
1 | private void startNonGui(String testFile, String logFile, CLOption remoteStart, boolean generateReportDashboard) |
那么我们再来看runNonGui
在干什么,它是真的要开始跑性能测试了,首先是对于 TestPlan 的 HashTree
的解析,获取需要的相关信息和再做一些初始化,如何解析HashTree
这个我们在之前的 HashTree
中已经介绍过了, 最后的核心是调用如下代码来启动 JMeter 测试
1 | if (!remoteStart) { |
我们看到首先会区分是不是 Remote 模式,我们这里只看非Remote的场景。engine.runTest()
这个是一个异步的调用,实际是启动一个线程,这个具体下次谈StandardJmeterEngine
的时候来看
startUdpDdaemon(engines)
是一个JMeter
管理服务,用来管理 Jmeter 的运行状况,例如Shutdown/StopTestNow/HeapDump/ThreadDump
等,这个样的设计让整个JMeter
的管理和JMeter
自身的进程实现了解耦。
好,下一次我们来看一下 StandardJMeterEngine
的实现