JMeter5.1启动类NewDriver源代码分析

2021-12-03 16:46:37 浏览数 (1)

概述

启动JMeter,主要通过NewDriver来实现,直接用于本地 GUI 和非 GUI 调用。

启动类主要做启动时设置项目目录,加载lib目录下的所有依赖包,并反射调用JMeter类的start()方法。

代码位置

image.pngimage.png

代码解读

主要变量

代码语言:txt复制
    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);
    // 获取java classPath
    private static final String JAVA_CLASS_PATH = "java.class.path";
    // 获取jmeter的logfile
    private static final String JMETER_LOGFILE_SYSTEM_PROPERTY = "jmeter.logfile";

    private static final String HEADLESS_MODE_PROPERTY = "java.awt.headless";

    // 动态加载器,主要加载Java依赖包
    private static final DynamicClassLoader loader;

    private static final String JMETER_INSTALLATION_DIRECTORY; // JMeter的安装路径

    private static final List<Exception> EXCEPTIONS_IN_INIT = new ArrayList<>();

静态代码块

主要是加载lib目录下的所有依赖包

代码语言:txt复制
static {
        final List<URL> jars = new LinkedList<>();
        final String initiaClasspath = System.getProperty(JAVA_CLASS_PATH);

        // Find JMeter home dir from the initial classpath
        String tmpDir;
        // 将获取的classPath进行拆分,分组
        StringTokenizer tok = new StringTokenizer(initiaClasspath, File.pathSeparator);
        if (tok.countTokens() == 1
                || (tok.countTokens()  == 2 // Java on Mac OS can add a second entry to the initial classpath
                    && OS_NAME_LC.startsWith("mac os x")// $NON-NLS-1$
                   )
           ) {
            File jar = new File(tok.nextToken());
            try {
                // JMeter启动类默认找当前文件路径的父目录
                tmpDir = jar.getCanonicalFile().getParentFile().getParent();
            } catch (IOException e) {
                tmpDir = null;
            }
        } else {// e.g. started from IDE with full classpath
        	/*
        	 * JMeter启动类默认找当前文件路径的父目录,由于生成的ApacheJMeter.jar启动包放置到JMeter的bin目录,所以获取的父目录正好是项目当前的目录,
        	 * 但是我们要调用的时候要手动设置jmeter.home这个属性,否则启动会报错
        	 */
            tmpDir = System.getProperty("jmeter.home","");// Allow override $NON-NLS-1$ $NON-NLS-2$
            if (tmpDir.length() == 0) {
                File userDir = new File(System.getProperty("user.dir"));// $NON-NLS-1$
                tmpDir = userDir.getAbsoluteFile().getParent();
            }
        }
        // JMeter项目路径
        JMETER_INSTALLATION_DIRECTORY=tmpDir;

        /*
         * Does the system support UNC paths? If so, may need to fix them up
         * later
         */
        boolean usesUNC = OS_NAME_LC.startsWith("windows");// $NON-NLS-1$

        // Add standard jar locations to initial classpath
        // 获取lib目录下的所有依赖包
        StringBuilder classpath = new StringBuilder();
        File[] libDirs = new File[] { new File(JMETER_INSTALLATION_DIRECTORY   File.separator   "lib"),// $NON-NLS-1$ $NON-NLS-2$
                new File(JMETER_INSTALLATION_DIRECTORY   File.separator   "lib"   File.separator   "ext"),// $NON-NLS-1$ $NON-NLS-2$
                new File(JMETER_INSTALLATION_DIRECTORY   File.separator   "lib"   File.separator   "junit")};// $NON-NLS-1$ $NON-NLS-2$
        for (File libDir : libDirs) {
            File[] libJars = libDir.listFiles((dir, name) -> name.endsWith(".jar"));
            if (libJars == null) {
                new Throwable("Could not access "   libDir).printStackTrace(); // NOSONAR No logging here
                continue;
            }
            Arrays.sort(libJars); // Bug 50708 Ensure predictable order of jars
            for (File libJar : libJars) {
                try {
                    String s = libJar.getPath();

                    // Fix path to allow the use of UNC URLs
                    if (usesUNC) {
                        if (s.startsWith("\\") && !s.startsWith("\\\")) {// $NON-NLS-1$ $NON-NLS-2$
                            s = "\\"   s;// $NON-NLS-1$
                        } else if (s.startsWith("//") && !s.startsWith("///")) {// $NON-NLS-1$ $NON-NLS-2$
                            s = "//"   s;// $NON-NLS-1$
                        }
                    } // usesUNC

                    jars.add(new File(s).toURI().toURL());// See Java bug 4496398
                    classpath.append(CLASSPATH_SEPARATOR);
                    classpath.append(s);
                } catch (MalformedURLException e) { // NOSONAR
                    EXCEPTIONS_IN_INIT.add(new Exception("Error adding jar:" libJar.getAbsolutePath(), e));
                }
            }
        }

        // ClassFinder needs the classpath
        System.setProperty(JAVA_CLASS_PATH, initiaClasspath   classpath.toString());

        // 通过加载器将所有jar包加载到类加载器中
        loader = AccessController.doPrivileged(
                (PrivilegedAction<DynamicClassLoader>) () ->
                        new DynamicClassLoader(jars.toArray(new URL[jars.size()]))
        );
    }

主要方法

加载外部依赖包

根据文件URL动态加载到loader

代码语言:txt复制
    public static void addURL(URL url) {
        loader.addURL(url);
    }

根据包的文件目录,获取当前文件路径及子路径的依赖包,转换为URL,并加载到loader中

代码语言:txt复制
    public static void addURL(String path) throws MalformedURLException {
        File furl = new File(path);
        loader.addURL(furl.toURI().toURL()); // See Java bug 4496398
        File[] jars = listJars(furl);
        for (File jar : jars) {
            loader.addURL(jar.toURI().toURL()); // See Java bug 4496398
        }
    }

获取JMeter项目路径

代码语言:txt复制
    public static String getJMeterDir() {
        return JMETER_INSTALLATION_DIRECTORY;
    }

启动JMeter程序

通过Java反射的方法创建JMeter类,执行其start()方法

代码语言:txt复制
    public static void main(String[] args) {
        if(!EXCEPTIONS_IN_INIT.isEmpty()) {
            System.err.println("Configuration error during init, see exceptions:" exceptionsToString(EXCEPTIONS_IN_INIT)); // NOSONAR Intentional System.err use
        } else {
            // 设置当前线程的类加载器
            Thread.currentThread().setContextClassLoader(loader);
            
            // 根据输入的外部参数,初始化日志文件
            setLoggingProperties(args);

            try {
                // Only set property if it has not been set explicitely 
                if(System.getProperty(HEADLESS_MODE_PROPERTY) == null && shouldBeHeadless(args)) {
                    System.setProperty(HEADLESS_MODE_PROPERTY, "true");
                }

                // 通过Java反射的方法创建JMeter类,并执行start()方法
                Class<?> initialClass = loader.loadClass("org.apache.jmeter.JMeter");// $NON-NLS-1$
                Object instance = initialClass.getDeclaredConstructor().newInstance();
                Method startup = initialClass.getMethod("start", new Class[] { new String[0].getClass() });// $NON-NLS-1$
                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); // NOSONAR Intentional System.err use
            }
        }
    }

0 人点赞