Jmeter源码系列(1)-NewDriver类详解-Jmeter 的启动器
写在前面的话
Jmeter 全称(Apache JMeter)是一个开源的、功能强大的性能测试工具,用于对各种应用程序和协议进行功能、负载、压力和性能测试。它被广泛应用于软件开发和计划阶段,以确保应用程序在各种负载情况下的稳定性和可靠性。
本系列将从 Jmeter 代码层面陆续剖析其实现原理,包括但不限于 Jmeter 设计思路,Jmeter 核心对象/接口/方法。如有错误,敬请指正!
NewDriver
NewDriver 是 org.apache.jmeter 包下的一个类,如下是 NewDriver 源码中的类说明
从这个说明中,我们可以知道,这个类提供了 2 个主要功能:
- 初始化 classpath
- 初始化一个 loader, 这个 loader 其实就是一个动态类加载器
以下内容摘抄自 NewDriver 源码,在源码中会使用注释来说明关键代码的作用,最后也会做总结,让我们开始吧
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 
 | public final class NewDriver {
 
 
 
 private static final String CLASSPATH_SEPARATOR = File.pathSeparator;
 private static final String OS_NAME = System.getProperty("os.name");
 private static final String OS_NAME_LC = OS_NAME.toLowerCase(java.util.Locale.ENGLISH);
 private static final String JAVA_CLASS_PATH = "java.class.path";
 private static final String JMETER_LOGFILE_SYSTEM_PROPERTY = "jmeter.logfile";
 private static final String HEADLESS_MODE_PROPERTY = "java.awt.headless";
 
 
 
 
 private static final DynamicClassLoader loader;
 private static final String JMETER_INSTALLATION_DIRECTORY;
 private static final List<Exception> EXCEPTIONS_IN_INIT = new ArrayList<>();
 
 static {
 final List<URL> jars = new ArrayList<>();
 
 
 
 final String initiaClasspath = System.getProperty(JAVA_CLASS_PATH);
 String tmpDir;
 
 
 
 
 
 
 StringTokenizer tok = new StringTokenizer(initiaClasspath, File.pathSeparator);
 
 
 
 if (tok.countTokens() == 1|| (tok.countTokens()  == 2 && OS_NAME_LC.startsWith("mac os x"))) {
 File jar = new File(tok.nextToken());
 try {
 tmpDir = jar.getCanonicalFile().getParentFile().getParent();
 } catch (IOException e) {
 tmpDir = null;
 }
 } else {
 
 
 
 
 tmpDir = System.getProperty("jmeter.home", System.getenv("JMETER_HOME"));
 if (tmpDir == null || tmpDir.length() == 0) {
 File userDir = new File(System.getProperty("user.dir"));
 tmpDir = userDir.getAbsoluteFile().getParent();
 }
 }
 if (tmpDir == null) {
 tmpDir = System.getenv("JMETER_HOME");
 }
 JMETER_INSTALLATION_DIRECTORY = tmpDir;
 boolean usesUNC = OS_NAME_LC.startsWith("windows");
 StringBuilder classpath = new StringBuilder();
 
 
 
 File[] libDirs = new File[] { new File(JMETER_INSTALLATION_DIRECTORY + File.separator + "lib"),
 new File(JMETER_INSTALLATION_DIRECTORY + File.separator + "lib" + File.separator + "ext"),
 new File(JMETER_INSTALLATION_DIRECTORY + File.separator + "lib" + File.separator + "junit")};
 for (File libDir : libDirs) {
 File[] libJars = libDir.listFiles((dir, name) -> name.endsWith(".jar"));
 if (libJars == null) {
 new Throwable("Could not access " + libDir).printStackTrace();
 continue;
 }
 
 
 
 Arrays.sort(libJars);
 for (File libJar : libJars) {
 try {
 String s = libJar.getPath();
 if (usesUNC) {
 if (s.startsWith("\\\\") && !s.startsWith("\\\\\\")) {
 s = "\\\\" + s;
 } else if (s.startsWith("//") && !s.startsWith("///")) {
 s = "//" + s;
 }
 }
 jars.add(new File(s).toURI().toURL());
 classpath.append(CLASSPATH_SEPARATOR);
 classpath.append(s);
 } catch (MalformedURLException e) {
 EXCEPTIONS_IN_INIT.add(new Exception("Error adding jar:"+libJar.getAbsolutePath(), e));
 }
 }
 }
 System.setProperty(JAVA_CLASS_PATH, initiaClasspath + classpath.toString());
 
 
 
 loader = AccessController.doPrivileged(
 (PrivilegedAction<DynamicClassLoader>) () ->
 new DynamicClassLoader(jars.toArray(new URL[jars.size()]))
 );
 }
 }
 
 | 
从上面的代码中,我们可以看到,NewDriver 在实例化时,会执行一个静态代码块,主要作用就是加载 Jmeter 安装目录下的 jar 包。
Main方法介绍
下面介绍 NewDriver 的 main 方法,这个方法就是整个 Jmeter 启动的入口方法。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 | 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 {
 
 
 
 if(System.getProperty(HEADLESS_MODE_PROPERTY) == null && shouldBeHeadless(args)) {
 System.setProperty(HEADLESS_MODE_PROPERTY, "true");
 }
 
 
 
 Class<?> initialClass = loader.loadClass("org.apache.jmeter.JMeter");
 
 
 
 Object instance = initialClass.getDeclaredConstructor().newInstance();
 
 
 
 Method startup = initialClass.getMethod("start", new Class[] { new String[0].getClass() });
 startup.invoke(instance, new Object[] { args });
 } catch(Throwable e){
 e.printStackTrace();
 System.err.println("JMeter home directory was detected as: "+JMETER_INSTALLATION_DIRECTORY);
 }
 }
 }
 
 | 
main 方法其实很简单直接,就是看下是不是要启动 GUI,然后就是通过反射调用 Jmeter 的 start 方法,来开始测试。
综上,NewDriver 其实就是一个启动器,正如其所在源码模块 launcher 一样,他的作用就是为 Jmeter 真正启动做好准备。
好了,NewDriver 就介绍完了,下一章将介绍 Jmeter 这个核心类,以及调用其 start(String[] args) 之后会发生什么…