指定java代理的类路径

时间:2017-12-22 23:03:09

标签: java jvm classpath instrumentation javaagents

对于上下文,我正在开发一个名为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

我尝试使用以下代码段在运行时打印出系统类路径:

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目录列为类路径的一部分,但是Random中的类replace/java/util无法找到?

1 个答案:

答案 0 :(得分:1)

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

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

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