将发布版合并为一个JAR文件的最简单方法

77
有没有一种工具或脚本可以轻松地将许多JAR文件合并成一个JAR文件?一个奖励是轻松设置主文件清单并使其可执行。
具体案例是一个Java重新结构化文本工具。我想用类似这样的东西来运行它:
java -jar rst.jar 据我所知,它没有依赖项,这表明它不应该是一个易于单个文件的工具,但下载的ZIP文件包含了很多库。
      0  11-30-07 10:01   jrst-0.8.1/
    922  11-30-07 09:53   jrst-0.8.1/jrst.bat
    898  11-30-07 09:53   jrst-0.8.1/jrst.sh
   2675  11-30-07 09:42   jrst-0.8.1/readmeEN.txt
 108821  11-30-07 09:59   jrst-0.8.1/jrst-0.8.1.jar
   2675  11-30-07 09:42   jrst-0.8.1/readme.txt
      0  11-30-07 10:01   jrst-0.8.1/lib/
  81508  11-30-07 09:49   jrst-0.8.1/lib/batik-util-1.6-1.jar
2450757  11-30-07 09:49   jrst-0.8.1/lib/icu4j-2.6.1.jar
 559366  11-30-07 09:49   jrst-0.8.1/lib/commons-collections-3.1.jar
  83613  11-30-07 09:49   jrst-0.8.1/lib/commons-io-1.3.1.jar
 207723  11-30-07 09:49   jrst-0.8.1/lib/commons-lang-2.1.jar
  52915  11-30-07 09:49   jrst-0.8.1/lib/commons-logging-1.1.jar
 260172  11-30-07 09:49   jrst-0.8.1/lib/commons-primitives-1.0.jar
 313898  11-30-07 09:49   jrst-0.8.1/lib/dom4j-1.6.1.jar
1994150  11-30-07 09:49   jrst-0.8.1/lib/fop-0.93-jdk15.jar
  55147  11-30-07 09:49   jrst-0.8.1/lib/activation-1.0.2.jar
 355030  11-30-07 09:49   jrst-0.8.1/lib/mail-1.3.3.jar
  77977  11-30-07 09:49   jrst-0.8.1/lib/servlet-api-2.3.jar
 226915  11-30-07 09:49   jrst-0.8.1/lib/jaxen-1.1.1.jar
 153253  11-30-07 09:49   jrst-0.8.1/lib/jdom-1.0.jar
  50789  11-30-07 09:49   jrst-0.8.1/lib/jewelcli-0.41.jar
 324952  11-30-07 09:49   jrst-0.8.1/lib/looks-1.2.2.jar
 121070  11-30-07 09:49   jrst-0.8.1/lib/junit-3.8.1.jar
 358085  11-30-07 09:49   jrst-0.8.1/lib/log4j-1.2.12.jar
  72150  11-30-07 09:49   jrst-0.8.1/lib/logkit-1.0.1.jar
 342897  11-30-07 09:49   jrst-0.8.1/lib/lutinwidget-0.9.jar
2160934  11-30-07 09:49   jrst-0.8.1/lib/docbook-xsl-nwalsh-1.71.1.jar
 301249  11-30-07 09:49   jrst-0.8.1/lib/xmlgraphics-commons-1.1.jar
  68610  11-30-07 09:49   jrst-0.8.1/lib/sdoc-0.5.0-beta.jar
3149655  11-30-07 09:49   jrst-0.8.1/lib/xalan-2.6.0.jar
1010675  11-30-07 09:49   jrst-0.8.1/lib/xercesImpl-2.6.2.jar
 194205  11-30-07 09:49   jrst-0.8.1/lib/xml-apis-1.3.02.jar
  78440  11-30-07 09:49   jrst-0.8.1/lib/xmlParserAPIs-2.0.2.jar
  86249  11-30-07 09:49   jrst-0.8.1/lib/xmlunit-1.1.jar
 108874  11-30-07 09:49   jrst-0.8.1/lib/xom-1.0.jar
  63966  11-30-07 09:49   jrst-0.8.1/lib/avalon-framework-4.1.3.jar
 138228  11-30-07 09:49   jrst-0.8.1/lib/batik-gui-util-1.6-1.jar
 216394  11-30-07 09:49   jrst-0.8.1/lib/l2fprod-common-0.1.jar
 121689  11-30-07 09:49   jrst-0.8.1/lib/lutinutil-0.26.jar
  76687  11-30-07 09:49   jrst-0.8.1/lib/batik-ext-1.6-1.jar
 124724  11-30-07 09:49   jrst-0.8.1/lib/xmlParserAPIs-2.6.2.jar

如您所见,手动操作并非理想选择。

到目前为止,我只尝试过AutoJar和ProGuard,它们都很容易上手。看起来JAR文件中的常量池存在一些问题。

显然jrst有点儿问题,因此我将努力修复它。 Maven pom.xml 文件似乎也有问题,因此在修复jrst之前我得先解决这个问题... 我觉得自己就像是一个吸引虫子的磁铁 :-)


更新:我从来没有解决过这个应用程序的问题,但我查看了Eclipse的“Runnable JAR导出向导”,它基于一个fat JAR。我发现这非常容易用于部署我的代码。
其他一些优秀的建议可能更适合在非Eclipse环境中进行构建,oss可能应该使用Ant进行良好的构建。(到目前为止,Maven只给了我痛苦,但其他人喜欢它。)

One-Jar - Stephen Denne
Fat Jar Eclipse插件 - Stephen Denne
http://www.jdotsoft.com/JarClassLoader.php - gorokhmn
13个回答

62

Ant的zipfileset可以胜任此工作。

<jar id="files" jarfile="all.jar">
    <zipfileset src="first.jar" includes="**/*.java **/*.class"/>
    <zipfileset src="second.jar" includes="**/*.java **/*.class"/>
</jar>

1
+1 因为这也允许添加 <manifest/> 标签并设置主类。 - Shirkrin
有没有办法以某种方式对目录中的所有Jar文件执行此操作? 这将非常方便,避免在库发生更改时更新build.xml。 - Frans Lundberg
3
尝试这种方法,您不必担心添加新的jar包:https://github.com/anupamsaini/Trie/blob/master/src/build.xml#L42 - Anupam Saini

34

Eclipse 3.4 JDT 的可运行 JAR 导出向导。

在 Eclipse 3.5 中,此功能进行了扩展。现在您可以选择如何处理所引用的 JAR 文件。


你能检查一下生成的ant脚本是否可用吗?之前有一个问题,是绝对文件路径而不是相对路径。 - Thorbjørn Ravn Andersen

27

经过尝试多种方法后,我发现One-JAR是最易于使用的解决方案,并成功地实现了我需要的功能:生成一个包含全部所需内容的单个可执行JAR文件。

One-JAR使用了自定义类加载器,可以浏览嵌套资源。查看下载中的.bat文件,其中org.codelutin.jrst.JRST在jrst-0.8.1.jar中是主要类,因此您的清单应如下所示:

Main-Class: com.simontuffs.onejar.Boot
One-Jar-Main-Class: org.codelutin.jrst.JRST

One-JAR可以处理命令行参数,这是一个非常酷的功能。假设你需要的所有资源都打包到单个JAR文件中,并且使用了自定义类加载器来处理类路径。

使用One-JAR最简单的方法是使用ant构建工具;有一个名为"one-jar"的自定义ant任务,其工作方式如下(假设您的清单文件名为"rst.mf"):

<target name="jar-rst">
    <one-jar destfile="rst.jar" manifest="rst.mf">
        <main jar="jrst-0.8.1.jar" />
        <lib>
            <fileset dir="${pathToJars}">
                <include name="batik-util-1.6-1.jar" />
                <include name="icu4j-2.6.1.jar" />
                <include name="commons-collections-3.1.jar" />
                <!-- Snip -->
            </fileset>
        </lib>
    </one-jar>
</target>

1
One-jar的脚本能力与ant相结合,使其可在持续构建系统中使用。 - Thorbjørn Ravn Andersen
  1. 如果我的jar文件中有多个应用程序(多个入口点类),One-JAR是否能够胜任?
  2. 如果另一个应用程序使用了这个jar文件,它是否也可以使用“One-JAR”中嵌套的jar文件中的类?
- MRalwasser

14
如果您是Maven用户,通常情况下装配插件会实现你所需要的功能,或者潜在地使用阴影插件,在某些情况下需要两者结合使用。
使用装配插件,您可以将一个包含必要设置的清单文件放置在您的项目中,尽管默认值通常很好。然后使用以下命令进行构建:
mvn assembly:assembly

如果您有更特殊的事情要处理,可以选择其他目标。Maven的依赖解析器会自动获取所有需要的JAR文件。如果使用shade插件,它通常是安装目标的一部分。我现在正在做的一个项目中就是这样。

mvn install
mvn assembly:single
< p > assembly:single目标是解决生命周期问题,在这种情况下是在Spring应用程序中。


9

有一个叫做ProGuard的工具,它不仅可以将您的JAR文件打包成一个文件,而且还可以优化、清理或混淆您的类文件,从而使得生成的JAR文件比之前的所有JAR文件的总和要小得多。

我曾经用JRST工具试过ProGuard,结果就像你所说的那样。我试图追踪问题,并发现它与jrst引用的ICU4J库中的一个错误有关。问题是,使用的ICU版本现在已经过时了。因此,我用ICU4J版本3.2替换了icu.jar文件。现在,ProGuard找到了一堆其他与JRST库不一致的错误/警告。

我的猜测是,ProGuard按预期工作,但是jrst的库并不一致。我不知道除了与开发人员交谈以外,您是否还能做更多的事情,因为他们应该检查和更新项目的依赖项。


谢谢!我已经下载并尝试过了,但在这个特定领域中,它会在icu4j-2.6.1.jar上出现未知常量字段错误。 - tovare

8
(基于安德里安的):
<jar id="files" jarfile="all.jar">
  <zipgroupfileset dir="${library.dir}" includes="*.jar" excludes="test-helper.jar"/>
  <zipfileset src="first.jar" includes="**/*.java **/*.class"/>
  <zipfileset src="second.jar" includes="**/*.java **/*.class"/>
  <fileset dir=".">
    <include name="LICENSE"/>
    <include name="NOTICE"/>
  </fileset>
</jar>

8
你可以使用 JarJar 工具,它使用包装技术来确保你的 JAR 文件不会与其他文件发生冲突。

5
One-JAR 0.97刚刚发布在http://one-jar.sourceforge.net,并且增加了对框架(如SpringGuice)的支持,这可能会给其他方法带来麻烦。它还处理类加载器反转——其中一些JAR文件是外部的(例如,JDBC驱动程序可能不会被捆绑在一起)。

One-JAR是命令行工具,具有AntMaven 2插件。也可以使用“jar”工具轻松构建。

我还可以推荐Eclipse Jar Exporter(Runnable),Ference Hechler写过关于它的评价:他在提出一种简单的方法来包装一组JAR文件方面做得很好。他和我一起工作在One-JAR上,但Jar Exporter基于不同的代码库。


3
有一个名为autojar的工具,它可以扫描您的字节码并编译包括引用(导入)类在内的.jar文件。

但是,在像Spring这样的框架中指定类名并由框架加载时,它并不总是有效。


谢谢你的指针,看起来这个特定应用程序中的一些 .jars 让我很头疼,难以完成此操作。 - tovare

3

或者使用Maven汇编插件(mvn assembly:assembly)


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