142

是否可以指定一个classpath包含另一个 JAR 文件中的 JAR 文件的 Java?

4

14 回答 14

100

如果您尝试创建一个包含您的应用程序及其所需库的 jar,有两种方法(我知道)可以做到这一点。第一个是One-Jar,它使用一个特殊的类加载器来允许 jar 的嵌套。第二个是UberJar,(或Shade),它会分解包含的库并将所有类放入顶级 jar 中。

我还应该提到 UberJar 和 Shade 分别是 Maven1 和 Maven2 的插件。如下所述,您还可以使用程序集插件(实际上它更强大,但更难正确配置)。

于 2008-10-08T15:12:05.863 回答
53

您不想使用那些“爆炸 JAR 内容”解决方案。它们肯定会让东西更难看(因为所有东西都在同一水平上爆炸)。此外,可能存在命名冲突(如果人们使用正确的包,则不应发生,但您不能总是控制这一点)。

您想要的功能是25 大 Sun RFE之一:RFE 4648386,Sun 以其无限的智慧将其指定为低优先级。我们只能希望太阳醒来......

同时,我遇到的最佳解决方案(我希望 Sun 将其复制到 JDK 中)是使用自定义类加载器JarClassLoader

于 2010-02-24T14:43:01.457 回答
32

经过一些研究,我发现了不需要 maven 或任何 3rd 方扩展/程序的方法。

您可以在清单文件中使用“类路径”。

例如:

创建清单文件 MANIFEST.MF

Manifest-Version: 1.0
Created-By: Bundle
Class-Path: ./custom_lib.jar
Main-Class: YourMainClass

编译所有类并运行jar cfm Testing.jar MANIFEST.MF *.class custom_lib.jar

c代表 create archive f表示要指定 file v是用于详细输入 m表示我们将传递自定义清单文件

确保在 jar 包中包含 lib。您应该能够以正常方式运行 jar。

基于:http ://www.ibm.com/developerworks/library/j-5things6/

你需要的关于类路径的所有其他信息都在这里找到

于 2014-02-14T10:49:45.710 回答
23

使用zipgroupfileset标签(使用与文件集标签相同的属性);它将解压缩目录中的所有文件并添加到您的新存档文件中。更多信息:http ://ant.apache.org/manual/Tasks/zip.html

这是解决 jar-in-a-jar 问题的一种非常有用的方法——我知道是因为我在试图弄清楚该怎么做时搜索了这个确切的 StackOverflow 问题。如果你想将一个 jar 或一个 jar 文件夹打包到你用 Ant 构建的 jar 中,那么忘记所有这些类路径或第三方插件的东西,你所要做的就是(在 Ant 中):

<jar destfile="your.jar" basedir="java/dir">
  ...
  <zipgroupfileset dir="dir/of/jars" />
</jar>
于 2011-09-09T14:09:19.197 回答
8

如果您正在使用 ant 构建(我正在使用来自 eclipse 的 ant),您可以通过告诉 ant 添加额外的 jar 文件来添加它们......如果您有一个由多人维护的项目,这不一定是最好的方法,但它可以工作对于一个人的项目,很容易。

例如,我构建 .jar 文件的目标是:

<jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
    <manifest>
        <attribute name="Author" value="ntg"/>
        ................................
        <attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
    </manifest>
</jar>

我只是添加了一行来实现它:

<jar ....">
    <zipgroupfileset dir="${external-lib-dir}" includes="*.jar"/>
    <manifest>
        ................................
    </manifest>
</jar>

在哪里

<property name="external-lib-dir" 
          value="C:\...\eclipseWorkspace\Filter\external\...\lib" />

是带有外部罐子的目录。就是这样……

于 2012-04-25T18:47:27.437 回答
6

并非没有编写自己的类加载器。您可以将 jars 添加到 jar 的类路径中,但它们必须位于同一位置,而不是包含在主 jar 中。

于 2008-10-08T15:10:45.850 回答
2

您需要构建一个自定义类加载器来执行此操作,或者构建一个支持此功能的第三方库。最好的办法是从运行时提取 jar 并将它们添加到类路径中(或者已经将它们添加到类路径中)。

于 2008-10-08T15:11:27.457 回答
2

我将 maven 用于我的 java 构建,它有一个名为maven assembly plugin的插件。

它可以满足您的要求,但就像其他一些建议所描述的那样-本质上是爆炸所有依赖的罐子并将它们重新组合成一个罐子

于 2008-10-08T17:53:43.977 回答
2

如果您有 eclpise IDE,您只需导出您的 JAR 并选择“将所需的库打包到生成的 JAR 中”。eclipse 会自动将所需的依赖 JAR 添加到生成的 JAR 中,并生成一些自动加载这些 JAR 的 eclipse 自定义类加载器。

于 2015-07-30T08:44:24.597 回答
1

我正要建议提取同一级别的所有文件,然后从结果中制作一个 jar,因为包系统应该将它们整齐地分开。那将是手动方式,我想史蒂夫指出的工具会很好地做到这一点。

于 2008-10-08T16:19:23.793 回答
1

Winstone 相当不错http://blog.jayway.com/2008/11/28/executable-war-with-winstone-maven-plugin/。但不适用于复杂的网站。这是一种耻辱,因为只需要包含插件。

于 2011-10-26T15:56:58.193 回答
1

好吧,如果您使用的是 Eclipse,那么有一个非常简单的方法。

将您的项目导出为“可运行”Jar 文件(在 Eclipse 中右键单击项目文件夹,选择“导出...”)。配置导出设置时,请务必选择“将所需库提取到生成的 Jar 中”。请记住,选择“提取...”而不是“打包所需的库...”。

另外:您必须在导出设置中选择运行配置。因此,您总是可以在某个类中创建一个空的 main() 并将其用于您的运行配置。

无论如何,它不能保证100% 的时间 - 因为您会注意到一条弹出消息,告诉您确保检查您包含的 Jar 文件的许可证以及不复制签名文件的一些内容。但是,我已经这样做了多年,从未遇到过问题。

于 2014-02-20T20:13:44.173 回答
0

提取到 Uber-dir 对我有用,因为我们都应该使用 root:\java 并且在带有版本控制的包中拥有 outlet 代码。即ca.tecreations-1.0.0。签名没问题,因为 jar 从其下载位置完好无损。3rd 方签名完整,解压到 c:\java。这是我的项目目录。从启动器运行 java -cp c:\java Launcher

于 2019-11-29T00:49:50.050 回答
0

如果您使用的是 Spring Boot,您可能需要查看以下文档:The Executable Jar Format

Java 不提供任何标准方法来加载嵌套的 jar 文件(即,本身包含在 jar 中的 jar 文件)。如果您需要分发可以从命令行运行而无需解包的独立应用程序,这可能会出现问题。

为了解决这个问题,许多开发人员使用“阴影”罐子。带阴影的 jar 将所有 jar 中的所有类打包到一个“uber jar”中。带阴影的 jar 的问题是很难看出哪些库实际上在您的应用程序中。如果在多个 jar 中使用相同的文件名(但内容不同),也可能会出现问题。Spring Boot 采用了不同的方法,让您实际上可以直接嵌套 jar

Spring 文档还列出了一些替代的单 Jar 解决方案

于 2021-05-04T19:30:43.950 回答