javaagent jar 在 bootclasspath 中的位置

发布于 2024-11-02 17:21:46 字数 586 浏览 5 评论 0原文

使用的 bootclasspath 上

Boot-Class-Path: myagent.jar

我有一个 javaagent jar,我将其放在MANIFEST.MF 文件内

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

但是,此处描述的方法并不似乎对我有用:

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

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

我正在使用 Java 6。

谁能告诉我如何获取 jar 的位置?

I have a javaagent jar that I put on the bootclasspath using

Boot-Class-Path: myagent.jar

inside the MANIFEST.MF file.

I need to find out the directory on the filesystem in which the jar is located.

However the method described for this here doesnt seem to work for me:

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

In this case the ProtectionDomain.getCodeSource() returns null. I guess this is happening because the jar has been put on the boot classpath. Because of this I also cannot do MyClass.getClassLoader() to get the resource location.

I am using Java 6.

Can anyone tell how to get the location of the jar?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别想她 2024-11-09 17:21:46

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

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

To find the location of MyClass.class on disk, do

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());

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

这是一个以 File 实例形式返回类文件路径的方法。如果类文件是 JAR 或 Java 运行时模块的一部分(URL 以协议 jrt: 开头),它只会返回 JAR 或 JMOD 文件的路径,这可能是您不想要的,但这只是一个展示,您可以根据自己的喜好进行编辑。当然,这仍然很棘手,例如,不考虑从 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

You can use the System class loader to find classes on the boot class path. For example, this

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

Will print out something like,

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

To find the location of MyClass.class on disk, do

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());

Update 2020-06-29 by kriegaex: Rather than writing a new answer to this old question, I want to enhance or update this very good answer, also taking account paths with spaces and Java 9+ modules.

Here is a method returning the class file path as a File instance. If a class file is part of a JAR or Java runtime module (URL starts with protocol jrt:), it just returns the paths to the JAR or to the JMOD file, which is something you might not want, but it is just a showcase you can edit to your heart's content. Of course this is still hacky, e.g. not considering classes loaded from a web URL instead of from file, but you get the idea.

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);
  }
}

When I call this from one of my IntelliJ IDEA projects with JDK 14 installed under a path containing spaces and deliberately adding a JAR also containing a path with spaces for testing, this code...

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)));
}

... yields this console output:

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
尸血腥色 2024-11-09 17:21:46

您可以执行以下操作:

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 文件并查看清单文件,看看它是否是您的。如果还没有独特的东西可供查找,您可以在清单中添加另一个条目来查找。

You could do something like this:

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);
}

Which goes through each entry in the boot classpath. For each entry you could then get the JAR file and look at the manifest file and see if it is yours. You could add another entry in the manifest to look for if there isn't already something unique to find.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文