Java求依赖jar的绝对路径

Java Find the absolute path of dependent jar

我有依赖于另一个项目 jar 的 Jar 文件。两者都是薄罐子,并且位于同一位置。第一个 jar 有清单文件,在其 class-path 属性.

中列出了第二个 jar

在第一个 jar 中,我在 java 中使用 ProcesBuilder class 作为进程启动第二个 jar。为此,我需要第二个罐子的绝对路径。在第一个罐子里我有 class XClient 如果我这样做 XClient.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath(); 我得到第一个罐子的绝对路径。然后我可以拆分并添加第二个 jar(硬编码)的名称来构建绝对路径

在第二个罐子里我有 class XServer 如果我这样做

 XServer .class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();

它抛出异常

我不确定我的方法是否正确,但我的目标很明确我想获得依赖 jar 的绝对路径。

请帮忙

我尝试使用相同的方法(但使用 File file=new File(this.getClass().getProtectionDomain().getCodeSource().toUri()) 而不是 getPath())但这可能会以不同的方式失败:

  1. 当 class 在 jar 中时,File 对象指向 jar 而不是 jar 所在的文件夹 - 因此需要 if(file.isFile()) file=file.getParentFile(); 来获取目录而不是 jar 文件
  2. 当 jar 文件由通常的 URLClassLoader 以外的其他东西加载时(上次我尝试回到 1.8 - 我只知道自从 Jigsaw 以来,主 classloader 不能转换为URLClassLoader)这可能会 return 一些未指定的结果,如果有的话,所以实际行为取决于系统设置 - 当在不受您控制的远程系统上使用时,这可能会使调试变得困难
  3. UNC 路径(Windows 共享)本身容易出错 - 在其上添加另一层(java)只会增加很多潜在的其他陷阱,你们都必须测试和调试- 通常最终你告诉客户使用什么以及如何设置而不是设计代码以遵循 java 原则:"write once, compile once, run everywhere"(顺便说一句:这也适用,即使你 "mount"网络共享,因此您可以通过本地驱动器盘符而不是远程网络路径来寻址它 - 但是当您尝试 link 两台机器(其中一台是另一台的克隆)时,这甚至会导致问题)
  4. 如评论所述:"it doesn'T work" 不是有用或有意义的描述 - 如果您收到错误消息(在这种情况下,您提到了异常堆栈跟踪)pos 一起使用生成它的代码(如果可访问)

我是如何解决我的问题的?我只是通过 swing JFileChooser 向用户询问目录/文件。是的,这不是万无一失的,也许不是最好的方法——但它可以工作,因为 swing 仍然与 SE JVM(而不是 FX)一起提供。 如果你想找到一条路径,请使用 Class.getResource() 并让 java 完成工作,就像加密一样:不要自己做。

除此之外:您提到的 "usecase" 不需要您尝试做的事情。您说服务器已经在 class 路径中 - 因此它会在启动时加载并且您可以访问 XServer class。最简单的方法不是分叉另一个进程,而是 运行 它在另一个线程中。如果你知道 class 有 main(server.jar 的清单会告诉你)并且你可以在 classpath 中访问它,只需这样做:

Thread serverThread=new Thread(new Runnable()
{
    public void run()
    {
        String[] args=Arrays.asList("required", "parameters");
        XServer.main(args);
    }
});
serverThread.start();

如果不需要参数,您可以只传递一个空字符串数组。因为 main() 不应该抛出异常(至少没有检查异常)所以不需要异常。

在所有 ose 评论都向我抛出之前:是的,我非常清楚 possible 问题,例如 classpath 问题(相同 classname in same packagename but different versions) 这样它可能比尝试找出绝对路径并启动 fork / sub 进程更可行。 另外:启动另一个进程可能需要与其流进行交互(向子进程输入流提供所需的输入并读取子进程输出流和错误流 - 否则分叉进程可能会 "hang" 因为它等待管道被清除。如果不是您自己的代码,调试此类问题是一件痛苦的事情,您可以附加一个分析器和调试器来找出为什么突然停止工作。

如果您真的想要(我认为没有任何强制 "you need to" 的要求)与客户端一起启动您的服务器,请使用 java 之外的启动脚本,但使用 os水平的东西。