类路径,包括 JAR 中的 JAR

是否可以指定一个 Javaclasspath,其中包含一个包含在另一个 JAR 文件中的 JAR 文件?

161518 次浏览

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

您需要构建一个自定义类装入器来完成此任务,或者构建一个支持此任务的第三方库。最好的办法是从运行时提取 jar 并将它们添加到类路径(或者已经将它们添加到类路径)。

如果您试图创建一个包含应用程序及其所需库的 jar,有两种方法(据我所知)可以做到这一点。第一个是 一罐,它使用一个特殊的类加载器来允许 jar 的嵌套。第二个是 UberJar,(或者 阴影) ,它将爆炸所包含的库,并将所有类放在顶级 jar 中。

我还应该提到 UberJar 和 Shade 分别是 Maven1和 Maven2的插件。正如下面提到的,您也可以使用汇编插件(实际上它功能更强大,但更难以正确配置)。

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

我使用 maven 来构建 java,它有一个名为 Maven 汇编插件的插件。

它可以按照你的要求做,但是就像其他一些建议描述的那样——本质上是将所有依赖的罐子爆炸,然后将它们重新组合成一个单独的罐子

您不希望使用那些“爆炸 JAR 内容”解决方案。它们肯定使得看东西变得更加困难(因为所有东西都在同一水平上爆炸)。此外,还可能存在命名冲突(如果人们使用正确的包就不应该发生这种情况,但是您不能总是控制这种情况)。

你想要的功能是 25大太阳射手: RFE 4648386之一,Sun 用他们无限的智慧,指定它为低优先级。我们只能希望 Sun 醒来..。

与此同时,我遇到的最好的解决方案(我希望 Sun 能够在 JDK 中复制它)是使用定制的类装入器 JarClassLoader

使用 Zipgroupfileset标记(使用与 文件集标记相同的属性) ; 它将解压缩目录中的所有文件并添加到新的归档文件中。 更多信息: < a href = “ http://ant.apache.org/Manual/Tasks/zip.html”rel = “ nofollow noReferrer”> http://ant.apache.org/manual/tasks/zip.html

这是一个非常有用的解决罐中罐问题的方法——我之所以知道这一点,是因为我曾在谷歌上搜索过这个确切的 StackOverflow 问题,同时试图找出应该做什么。如果你想用 Ant 把一个 jar 或者一个 jar 文件夹打包到你构建的 jar 中,那么忘掉所有这些类路径或者第三方插件吧,你所要做的就是(在 Ant 中) :

<jar destfile="your.jar" basedir="java/dir">
...
<zipgroupfileset dir="dir/of/jars" />
</jar>

Winstone 的 http://blog.jayway.com/2008/11/28/executable-war-with-winstone-maven-plugin/很不错。但是对于复杂的地点来说就不是这样了。这是一个耻辱,因为所有需要的是包含插件。

如果您正在使用 ant 构建(我正在使用 Eclipse 中的 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" />

就是放外部罐子的目录。 就是这样。

经过一些研究,我找到了一种不需要专家或任何第三方扩展/程序的方法。

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

例如:

创建清单文件 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代表创建归档文件 f表示要指定文件 v用于详细的输入 m意味着我们将传递自定义清单文件

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

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

你需要的关于类路径的所有其他信息你能找到 给你

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

将您的项目导出为“ Runnable”Jar 文件(右键单击 Eclipse 中的项目文件夹,选择“ Export...”)。配置导出设置时,请确保选择“将所需库提取到生成的 Jar 中”请记住,选择“ Extract...”和 没有“ Package 义务库...”。

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

无论如何,它不是 保证工作100% 的时间-因为你会注意到一个弹出消息告诉你,以确保你检查的 Jar 文件的许可证,你包括和一些关于不复制签名文件。然而,我一直这样做的 好几年了和从来没有遇到一个问题。

如果您拥有 Eclipse IDE,那么您只需要导出您的 JAR 并选择“ PackageRefied 库到生成的 JAR 中”。Eclipse 将自动将所需的依赖 JAR 添加到生成的 JAR 中,并生成一些 Eclipse 自定义类加载器,自动加载这些 JAR。

提取到一个 Uber-dir 对我来说很有用,因为我们都应该使用 root: java,并且在包中使用带版本控制的出口代码。1.0.签名是可以的,因为罐子从他们的下载位置是完整的。第三方签名完整,提取到 c: java。这就是我的项目导演。从启动程序运行 java-cp c: java 启动程序

如果您正在使用 SpringBoot,您可能需要查看以下文档: 可执行罐格式

Java 没有提供任何标准方法 来加载嵌套的 jar 文件(即 是,包含在 jar 中的 jar 文件) 如果您需要分发一个自包含的应用程序,就会出现问题 可以从命令行运行而不需要解压缩。

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

Spring 文档还列出了一些 可选择的单罐解决方案:

我建议使用一个 jar 和多个 jar 中的库,而不是在单个 jar 中。使用与 jar 库分开的 jar。
假设您有这样一个文件夹结构:

path/yourApp/yourApp.jar
path/yourApp/lib/lib1.jar
path/yourApp/lib/megalib1.jar
path/yourApp/lib/supermegalib1.jar

所有你必须做的,添加到 名单每个使用的罐子。

Manifest-Version: 1.0
Main-Class: com.company.MyProgram
Class-Path: ./lib/lib1.jar ./lib/megalib1.jar ./lib/supermegalib1.jar

在清单中,可以将使用权授予每个库。
在一个 jar 文件中使用单个 all 可能更容易共享和分发,但实际上这并不比将其作为归档文件分发并将其解压缩到您希望部署的某个文件夹中具有明显的优势。这不会使您的程序更容易维护、更快。它不会对 hdd 的使用产生重大影响。