【问题标题】:Reference jars inside a jar罐子内的参考罐子
【发布时间】:2012-09-03 15:23:21
【问题描述】:

我有一个 jar,其内容如下所示,

下面是我的清单文件

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.7.0_06-b24 (Oracle Corporation)
Main-Class: org.sai.com.DerbyDemo
Class-Path: derby.jar derbyclient.jar derbynet.jar derbytools.jar

当我尝试运行 jar 时,它抛出了 ClassNotFoundExcception,这意味着它没有引用外部 jar 中的 jar。

Class-Path 属性中,如何在实际的jar 中引用jar(derby.jar 等)?

【问题讨论】:

标签: java jar manifest executable-jar


【解决方案1】:

你需要一个自定义的类加载器,看看One Jar

One-JAR 让您可以将 Java 应用程序及其依赖项 Jar 打包到单个可执行 Jar 文件中。

它有一个蚂蚁任务,它也可以简化它的构建。

参考(来自background

大多数开发人员合理地假设将依赖 Jar 文件放入他们自己的 Jar 文件中,并向 META-INF/MANIFEST 添加 Class-Path 属性就可以解决问题


jarname.jar
| /META-INF
| |  MANIFEST.MF
| |    Main-Class: com.mydomain.mypackage.Main
| |    Class-Path: commons-logging.jar
| /com/mydomain/mypackage
| |  Main.class
| commons-logging.jar

很遗憾,这是行不通的。 Java Launcher$AppClassLoader 不知道如何使用这种Class-Path 从 Jar 中的 Jar 中加载类。尝试使用jar:file:jarname.jar!/commons-logging.jar 也会导致死胡同。此方法仅在您将支持的 Jar 文件安装(即分散)到安装 jarname.jar 文件的目录中时才有效。

【讨论】:

    【解决方案2】:

    你不能。来自official tutorial

    通过在清单中使用 Class-Path 标头,您可以避免 在调用 Java 以运行您的 应用。

    注意:Class-Path 标头指向目录上的类或 JAR 文件 本地网络,而不是 JAR 文件中的 JAR 文件或可访问的类 通过互联网协议。在 JAR 中加载 JAR 文件中的类 文件进入类路径,你必须编写自定义代码来加载那些 类。例如,如果 MyJar.jar 包含另一个名为 MyUtils.jar,您不能在 MyJar.jar 中使用 Class-Path 标头 manifest 将 MyUtils.jar 中的类加载到类路径中。

    【讨论】:

      【解决方案3】:

      在 Eclipse 中,您可以选择导出可执行的 jar。 您可以选择将所有与项目相关的 jar 打包到生成的 jar 中,这样 eclipse 添加自定义类加载器,它将引用您在新 jar 中集成的 jar。

      【讨论】:

      • @vogash 您是如何创建启动配置 MainActivity-asc_validation 的?就我而言,我有一个 Android 应用程序,我将其用作 jar 文件。这个 jar 文件又引用了多个其他 jar 文件。所以我试图使用这个选项。但是我被困在这一点上。我无法将 android 配置转换为启动配置。
      • 太棒了!这完美地工作,我不明白为什么没有更好地记录它!非常感谢 Vogash!
      • 确实有效。我正在做各种命令行猴子业务,但不知道 eclipse 有它......谢谢分享
      • 为此,在导出期间选择“可运行的 JAR 文件”(如上面的屏幕截图所示)而不是“JAR 文件”至关重要。
      【解决方案4】:

      类加载器的默认实现无法从 jar-within-a-jar 加载:为此,必须将整个“子 jar”加载到内存中,这破坏了随机访问的好处jar 格式(参考待定 - 一旦找到支持此的文档,我将进行编辑)。

      我建议使用 JarSplice 之类的程序将所有内容打包到一个干净的可执行 jar 中。

      编辑: 找不到源参考,但 Sun 网站上有一个未解决的 RFE,描述了这个确切的“问题”:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4648386

      此外,您可以通过将库 jar 文件放在您的 classes 目录的 \lib 子目录中,然后从命令行运行来“测试”您的程序是否正常工作。换句话说,具有以下目录结构:

      classes/org/sai/com/DerbyDemo.class
      classes/org/sai/com/OtherClassFiles.class
      classes/lib/derby.jar
      classes/lib/derbyclient.jar
      

      从命令行导航到上述“类”目录,然后键入:

      java -cp .:lib/* org.sai.com.DerbyDemo
      

      【讨论】:

        【解决方案5】:

        如果您不想创建自定义类加载器。您可以读取 jar 文件流。并将其传输到 File 对象。然后你可以得到文件的url。将其发送到 URLClassLoader,您可以根据需要加载 jar 文件。 示例:

        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("example"+ ".jar");
        final File tempFile = File.createTempFile("temp", ".jar");
        tempFile.deleteOnExit();  // you can delete the temp file or not
        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            IOUtils.copy(resourceAsStream, out);
        }
        IOUtils.closeQuietly(resourceAsStream);
        URL url = tempFile.toURI().toURL();
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
        urlClassLoader.loadClass()
        ...
        

        【讨论】:

          【解决方案6】:

          将 jar 文件添加到您的 库(如果使用 netbeans) 并修改您的清单文件 classpath,如下所示:

          Class-Path: lib/derby.jar lib/derbyclient.jar lib/derbynet.jar lib/derbytools.jar
          

          存在类似的答案here

          【讨论】:

            【解决方案7】:

            在eclipse中,右键项目,选择RunAs -> Run Configuration,保存运行配置,下次导出为Runnable JARs时会用到

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-02-01
              • 1970-01-01
              • 2012-12-28
              • 2020-03-15
              • 1970-01-01
              • 2013-06-19
              相关资源
              最近更新 更多