【问题标题】:Specifying the classpath for a java agent指定 java 代理的类路径
【发布时间】:2017-12-22 23:03:08
【问题描述】:

就上下文而言,我正在开发一个名为 Randoop 的工具。我需要做的是能够在运行时使用 Java 代理替换某些方法调用。具体来说,我想用 Random(0) 替换对 Random() 的调用。

我的目录结构如下:

test_randoop/
    randoop.jar
    replacecall.jar
    replacement_file.txt
    ClassWithRandom.java
    ClassWithRandom.class
    replace/
        java/
            util/
                Random.java
                Random.class   // created with "javac Random.java" command

我正在运行 test_randoop 目录中的所有命令。

Random.java的内容是:

package replace.java.util;

public class Random {
  /** Default mock for {@code Random()}. Replaces call with {@code Random(0)}. */
  public static java.util.Random randomWithSeedZero() {
    return new java.util.Random(0);
  }

  public static int returnZero() {
    return 0;
  }
}

我想在运行时使用以下行获取 Random 类,其中 classname 定义为 replace.java.util.Random

Class<?> methodClass = Class.forName(classname);

但是,此代码是从 replacecall.jar 文件中调用的,该文件是我用来替换调用的 Java 代理。这似乎是个问题,因为代理似乎不知道 replace.java.util.Random 类。

详细来说,我正在运行的 Java 程序是使用以下命令执行的:

java -ea -classpath .:randoop.jar -Xbootclasspath/a:/home/waylonh/test_randoop/replacecall.jar -javaagent:/home/waylonh/test_randoop/replacecall.jar="--replacement-file=replacement_file.txt --debug=true --verbose=true" randoop.main.Main gentests --testclass=ClassWithRandom --output-limit=10

问题是在类路径中永远找不到replace.java.util.Random 类,并且forName 方法会抛出ClassNotFoundException

我尝试在运行时使用以下 sn-p 打印出系统类路径:

ClassLoader classLoader = ClassLoader.getSystemClassLoader();
for (URL u : ((URLClassLoader) classLoader).getURLs()) {
  System.out.println(u.getFile());
}

结果输出是:

/home/waylonh/test_randoop/
/home/waylonh/randoop/build/libs/randoop-all-3.1.5.jar
/home/waylonh/randoop/build/libs/replacecall-3.1.5.jar

我会在这里遗漏什么?是否必须为 Java 代理参数提供不同的类路径?为什么系统类加载器将test_randoop目录列为classpath的一部分,却找不到replace/java/util中的Random类?

【问题讨论】:

    标签: java jvm classpath instrumentation javaagents


    【解决方案1】:

    引导类加载器(加载 JDK 类)和系统类加载器(加载应用程序类)是不同的东西。

    默认情况下,Java 代理由系统类加载器加载,它可以访问-classpath 中指定的类。但是在您的情况下,由于-Xbootclasspath 选项,代理由引导类加载器加载,并且它看不到来自系统类加载器的类。

    您基本上需要删除-Xbootclasspath,以便代理也可以看到用户类。

    【讨论】:

    • 感谢您的建议!如果我需要 -Xbootclasspath 选项以便代理可以看到 JDK 类怎么办?那么保留-Xbootclasspath 参数,有没有办法让Java 代理也可以看到系统类加载器中的类?
    • @wayway 即使没有-Xbootclasspath,代理也会看到 JDK 类。 ClassLoader 构成层次结构:Bootstrap -> System -> Application ClassLoader。子类加载器加载的类可以访问父类加载器的所有类。
    猜你喜欢
    • 1970-01-01
    • 2018-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-31
    相关资源
    最近更新 更多