如何将库与我的jar文件结合?

4

好的,我写了一个使用第三方开源库的程序,并希望将其与我的程序一起打包到单个jar文件中。我正在使用Netbeans 6.8,但无论我尝试什么方法,Java都会返回错误:

java.lang.NoClassDefFoundError: libraryname;
离题了: 我还想知道如何通过NetBeans制作可执行的JAR(exe)文件,如果可能的话。(我看过用Java编写的程序,但是它们是.exe文件。) 编辑:我发现Eclipse有一个名为FatJar的插件可以做到我想要的,但我找不到类似的东西适用于NetBeans,是否存在这样的东西?

1
你的问题不是主题相关的,可以在https://dev59.com/SHI-5IYBdhLWcg3wHUdB找到答案...但我认为你不能使用Netbeans实现这个。 - Stephen C
这可能是一个重复的问题,与此类似:https://dev59.com/9nVD5IYBdhLWcg3wHnyd。 - bryantsai
7个回答

17
我会先声明一下:Java可执行JAR文件并不是这样工作的。一个可执行JAR在JAR文件的MANIFEST.MF文件中定义了一个主类,MANIFEST还允许定义类路径以包含可执行JAR中代码所需的库。MANIFEST中的类路径定义必须列出要放置在类路径上的每个JAR文件或文件夹,相对路径是相对于可执行JAR的位置而不是在可执行JAR内部的路径。可执行JAR通过使用"-jar"参数启动java可执行文件,并且无论是java的"-cp"标志还是CLASSPATH环境变量都将被忽略。至于为什么设计可执行JAR是这样的,您应该了解从JAR文件中加载类的主要缺点,即使本回复的其余部分将专注于这样做。
注意:我丢失了原始的sun论坛主题,它完全解释了这一点,但基本上是因为可以以随机访问方式读取顶层JAR中的条目,但在访问任何条目之前必须读取整个嵌入式JAR,因为顶层JAR可能已压缩其条目。

我曾经成功使用过One-Jar,但最终结果的JAR文件结构可能不是你所期望的。基本上,One-Jar类是最终JAR文件中唯一没有以JAR格式打包的类;所有其他代码(你的代码和任何依赖库的代码)都被包含在生成的JAR文件中作为JAR文件存在。你的应用程序被打包成一个名为"main.jar"的常规JAR文件,并放置在最终JAR文件的"main"文件夹中。你的代码所需的任何库文件也以JAR文件形式,被放置在最终JAR文件的"lib"文件夹中。最后但并非最不重要的是,最终JAR文件的MANIFEST.MF文件告诉One-Jar你的主类是什么。执行很简单,只需使用命令"java -jar final.jar [你的应用所使用的参数]"。关于你的离题问题如何转换为操作系统原生EXE,我不知道该如何进行下一步,但无论如何最好使用与One-Jar不同的打包机制。至于如何在NetBeans中进行此操作,我不确定,我的建议是使用构建工具来打包最终JAR文件。幸运的是,One-Jar提供了使用Ant生成最终JAR文件的说明,这应该很容易集成到NetBeans中。

我认为Eclipse的FatJar插件可以创建一个One-Jar可执行JAR文件,所以如果该插件似乎符合你的需求,那么使用One-Jar是做到这一点的方法。个人使用了Maven汇编。

需要注意的是 - 任何需要(或希望)利用Java签名JAR验证的已签名库可能无法按照此方式工作 - Java加密扩展(JCE)实现如BouncyCastle就是一个显著的例子。我认为原因是签名验证针对的是最终的JAR文件,而不是已签名的库文件。幸运的是,One-Jar允许最终用户将其他库文件添加到类路径中,当运行可执行的JAR文件时,这是明确禁止的;为了解决这个问题,你最好将有问题的JAR文件与最终JAR文件以及一个依赖于操作系统的启动脚本(.bat、.sh等)一起提供给用户。


1
One-jar 确实是我见过追求这种不明智课程的最佳方式 ;) +1 - erickson

4
我知道这并不完全符合你的要求,但我将描述分发独立应用程序的惯常方法。如果它能满足您的需求,您会发现它比自定义方法更好地得到支持,并且更容易被用户理解,因为它遵循已建立的惯例。
将您的代码放入一个 jar 包中(我称之为 app.jar),并在其中添加一个包含以下条目的 META-INF/MANIFEST.MF 文件:
Main-Class: com.y.app.AppMain
Class-path: third-party.jar blort.jar foo.jar

接下来,你可以把所有的jar包放到一个目录中,然后像这样运行AppMain

java -jar app.jar

如果您愿意,可以将第三方库放在一个单独的目录中,例如lib,并在Class-path属性中使用相对于主JAR文件的路径引用它们:lib/third-party.jar。这有助于使您的分发更加整洁。

是的,这就是我目前拥有的结构,我想将该库嵌入到我的主要JAR包中。 - Dacto

4

3

如果您想在您的jar包中包含另一个jar包,您可能会发现jarjar非常有用。

可执行的jar包只需要定义一个名为“Main”的类即可,如果我没记错的话。 这可能会有所帮助


关于如何使用jarjar的信息并不清楚,无法完成这个任务。我还注意到谷歌代码上的其他用户也在遇到jarjar缺乏示例/文档的问题。你能解释一下如何使用jarjar来做这个吗? - Dacto

1

如果没有将第三方JAR包重新打包到最终的大JAR包中的担忧,那么this应该是最简单的方法。


0
如果没有许可问题,最好的方法是解压实际的jar文件,将您的类文件重新打包到一个新的jar文件中。
您可以简单地使用jar命令来完成这个操作,没什么大不了的!

1
我该如何完成这个任务?我知道我可以提取内容,但是接下来就不知道该怎么做了... - Dacto
我不同意。对于开发人员来说,这可能很简单,但对于需要用不同版本替换第三方库的用户来说,这是一个障碍。这就是为什么很多开源许可证会反对/限制/禁止这种嵌入方式的原因! - Stephen C
好的,那我回到原来的地方了 :) - Dacto
@Dacto - 我在谈论的是解压第三方JAR并将其内容与您的应用程序类混合的做法。相比之下,仅将第三方JAR嵌入您的JAR更为规范。 - Stephen C
是的,我知道你的意思,我不知道如何嵌入第三方jar包,但我的程序仍然可以正常运行。 - Dacto
@stephen...这就是为什么我的回答以“如果没有许可问题…”开头的原因:)。至于另一点,我认为这不是最终用户的工作,而是产品集成团队的工作,如果他们有这样的团队的话:)。 - Suraj Chandran

0
如果您使用MAVEN,请使用“maven-shade-plugin”插件。它将编译包含所有依赖项(第三方等)的JAR文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接