【问题标题】:Location of javaagent jar in bootclasspathjavaagent jar 在 bootclasspath 中的位置
【发布时间】:2011-08-09 06:35:51
【问题描述】:

我有一个 javaagent jar,我使用

将它放在 bootclasspath 中
Boot-Class-Path: myagent.jar

在 MANIFEST.MF 文件中。

我需要找出 jar 所在文件系统上的目录。

但是,为此 here 描述的方法似乎对我不起作用:

 new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().g­etPath());

在这种情况下,ProtectionDomain.getCodeSource() 返回 null。我猜这是因为 jar 已被放在引导类路径中。因此,我也无法执行 MyClass.getClassLoader() 来获取资源位置。

我正在使用 Java 6。

谁能告诉我如何获得罐子的位置?

【问题讨论】:

  • 我知道 cmets 在这里只说“谢谢”是不受欢迎的,但因为我看到你提到Boot-Class-Path,我很好奇,收集到的信息帮助我优雅地解决了代理引导程序的问题注射。我使用大量样板代码手动完成了后者,现在只要用户在将其用作代理 JAR 之前不修改工件名称,它就可以工作。所以谢谢!

标签: java classloader bytecode instrumentation javaagents


【解决方案1】:

你可以这样做:

final String   bootClassPath;
final String[] entries;

// different VM may use a different string here...
bootClassPath = System.getProperty("sun.boot.class.path");
entries       = bootClassPath.split(File.pathSeparator);

for(final String entry : entries)
{
    System.out.println(entry);
}

通过引导类路径中的每个条目。对于每个条目,您可以获取 JAR 文件并查看清单文件,看看它是否是您的。您可以在清单中添加另一个条目以查找是否还没有独特的东西可以找到。

【讨论】:

  • RuntimeMXBean.getBootClassPath 可能更好。
  • 可能......我已经很久没有关心引导类路径了......我没有跟上最新的信息。无论如何,另一个答案比我的要好(只是保留这个答案,以防它在某个时间点帮助某人做某事:-)
【解决方案2】:

您可以使用系统类加载器在引导类路径上查找类。比如这个

System.out.println(
  ClassLoader.getSystemClassLoader().getResource("java/lang/String.class")
);

会打印出类似的东西,

jar:file:/C:/Program%20Files/Java/jdk1.6.0_22/jre/lib/rt.jar!/java/lang/String.class

要在磁盘上找到MyClass.class 的位置,请执行

String urlString = ClassLoader
 .getSystemClassLoader()
 .getResource("com/my/package/MyClass.class")
 .toString();

urlString = urlString.substring(urlString.indexOf("file:"), urlString.indexOf('!'));
URL url = new URL(urlString);
File file = new File(url.toURI());
System.out.println(file);
System.out.println(file.exists());

kriegaex

更新 2020-06-29:我不想为这个老问题写一个新的答案,而是想增强或更新这个非常好的答案,同时采取带有空格和 Java 9+ 模块的帐户路径。

这是一个将类文件路径作为File 实例返回的方法。如果类文件是 JAR 或 Java 运行时模块的一部分(URL 以协议 jrt: 开头),它只会返回 JAR 或 JMOD 文件的路径,这可能是您不想要的,但它只是一个展示您可以编辑到您心中的内容。当然,这仍然是 hacky,例如不考虑从 Web URL 而不是从文件加载的类,但你明白了。

public static File getFileForClass(String className) {
  className = className.replace('.', '/') + ".class";
  URL classURL = ClassLoader.getSystemClassLoader().getResource(className);
  if (classURL == null)
    return null;
  System.out.println("Class file URL: " + classURL);

  // Adapt this if you also have '.war' or other archive types
  if (classURL.toString().contains(".jar!")) {
    String jarFileName = classURL.getPath().replaceFirst("!.*", "");
    System.out.println("Containing JAR file: " + jarFileName);
    try {
      return new File(new URL(jarFileName).toURI());
    }
    catch (URISyntaxException | MalformedURLException e) {
      throw new RuntimeException(e);
    }
  }

  if (classURL.getProtocol().equals("jrt")) {
    String jrtModule = classURL.getFile().replaceFirst("/([^/]+).*", "$1");
    System.out.println("Target class is part of Java runtime module " + jrtModule);
    String jmodName = System.getProperty("java.home") + "/jmods/" + jrtModule + ".jmod";
    System.out.println("Containing Java module file: " + jmodName);
    return new File(jmodName);
  }
  try {
    return new File(classURL.toURI());
  }
  catch (URISyntaxException e) {
    throw new RuntimeException(e);
  }
}

当我从我的一个 IntelliJ IDEA 项目中调用它时,JDK 14 安装在包含空格的路径下,并故意添加一个 JAR 也包含带有空格的路径以进行测试,这段代码...

public static void main(String[] args) throws IOException {
  Instrumentation instrumentation = ByteBuddyAgent.install();
  instrumentation.appendToSystemClassLoaderSearch(
    new JarFile("C:/Program Files/JetBrains/IntelliJ IDEA 2018.3/lib/idea_rt.jar")
  );
  Stream
    .of(
      Weaver.class.getName(),
      String.class.getName(),
      ByteBuddy.class.getName(),
      "com.intellij.execution.TestDiscoveryListener"
    )
    .forEach(className -> System.out.printf("Found file: %s%n%n", getFileForClass(className)));
}

... 产生此控制台输出:

Class file URL: file:/C:/Users/alexa/Documents/java-src/Sarek/sarek-aspect/target/classes/dev/sarek/agent/aspect/Weaver.class
Found file: C:\Users\alexa\Documents\java-src\Sarek\sarek-aspect\target\classes\dev\sarek\agent\aspect\Weaver.class

Class file URL: jrt:/java.base/java/lang/String.class
Target class is part of Java runtime module java.base
Containing Java module file: C:\Program Files\Java\jdk-14.0.1/jmods/java.base.jmod
Found file: C:\Program Files\Java\jdk-14.0.1\jmods\java.base.jmod

Class file URL: jar:file:/C:/Users/alexa/.m2/repository/net/bytebuddy/byte-buddy/1.10.13/byte-buddy-1.10.13.jar!/net/bytebuddy/ByteBuddy.class
Containing JAR file: file:/C:/Users/alexa/.m2/repository/net/bytebuddy/byte-buddy/1.10.13/byte-buddy-1.10.13.jar
Found file: C:\Users\alexa\.m2\repository\net\bytebuddy\byte-buddy\1.10.13\byte-buddy-1.10.13.jar

Class file URL: jar:file:/C:/Program%20Files/JetBrains/IntelliJ%20IDEA%202018.3/lib/idea_rt.jar!/com/intellij/execution/TestDiscoveryListener.class
Containing JAR file: file:/C:/Program%20Files/JetBrains/IntelliJ%20IDEA%202018.3/lib/idea_rt.jar
Found file: C:\Program Files\JetBrains\IntelliJ IDEA 2018.3\lib\idea_rt.jar

【讨论】:

  • 路径中有空格时不起作用,例如 jar:file:/C:/test%20recorder/recorder2/jar/recorder-1.0.0-beta-build86.jar!/com /chronon/sb/recorder/RecorderMain.class。在这种情况下,制作一个新的 File("C:/test%20recorder/recorder2/jar/recorder-1.0.0-beta-build86.jar").exists() 返回 false
  • 你只需要取消转义网址,stackoverflow.com/questions/623861/…
  • 在 url.substring() 中你做了 "file:".length() + 1,不会 +​​1,删除 unix 文件系统上的开头 '/'?
  • 注意:URLDecoder 不能用于对 URL 进行转义(它会将 + 转换为错误的空格)。处理 URL 的正确方法是 url.toURI().getSchemeSpecificPart()(它将返回解码后的 url)
  • 我冒昧地为这个非常好的答案添加了更多示例代码,同时考虑了带有空格和 Java 9+ 模块的路径。我不想写一个新答案并从这个答案中窃取声誉。我希望编辑没问题 - 无意冒犯。否则@sbridges 可以恢复它。
猜你喜欢
  • 2018-06-25
  • 2018-01-24
  • 2011-07-18
  • 1970-01-01
  • 2014-10-14
  • 1970-01-01
  • 2014-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多