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

Posted

技术标签:

【中文标题】将发布合并到一个 JAR 文件中的最简单方法【英文标题】:Easiest way to merge a release into one JAR file 【发布时间】:2010-09-10 00:33:54 【问题描述】:

是否有工具或脚本可以轻松地将一堆 JAR 文件合并到一个 JAR 文件中?一个好处是可以轻松设置主文件清单并使其可执行。

具体案例是Java restructured text tool。我想用类似的东西来运行它:

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 的“可运行 JAR 导出向导”,它基于一个胖 JAR。我发现这很容易用于部署我自己的代码。

其他一些优秀的建议可能更适合在非 Eclipse 环境中构建,oss 可能应该使用Ant 构建一个不错的构建。 (Maven,到目前为止只是让我感到痛苦,但其他人喜欢它。)

【问题讨论】:

One-Jar Fat Jar Eclipse Plugin jdotsoft.com/JarClassLoader.php 【参考方案1】:

Ant 的 zipfileset 完成这项工作

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

【讨论】:

+1 因为这也允许添加 标签并设置主类。 是否有可能以某种方式对目录中的所有 jar 文件执行此操作。会很整洁。避免在库更改时更新 build.xml。 试试这个方法,你就不用担心添加新的 jar 了:github.com/anupamsaini/Trie/blob/master/src/build.xml#L42【参考方案2】:

Eclipse 3.4 JDT 的 Runnable JAR 导出向导。

在 Eclipse 3.5 中,这已被扩展。现在您可以选择如何处理引用的 JAR 文件。

【讨论】:

能否检查生成的ant脚本是否可用?之前有一个绝对文件路径而不是相对文件路径的问题。【参考方案3】:

尝试了几种不同的解决方案后,我发现One-JAR 最容易使用,并且成功地做到了这一点:生成一个包含我需要的所有内容的单个可执行 JAR。

One-JAR 使用自定义类加载器,可以导航嵌套资源。查看下载中的.bat文件,看起来jrst-0.8.1.jar中的org.codelutin.jrst.JRST是主类,所以你的manifest应该是这样的:

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>

【讨论】:

one-jar 与 ant 的可脚本性使其可用于连续构建系统。 1.如果我的 jar 中有多个应用程序(几个入口点类),One-JAR 是否支持? 2. 如果这个jar被另一个应用程序使用了,它是否也可以使用“One-JAR”内嵌套jar中的类?【参考方案4】:

如果您是Maven 用户,通常汇编插件会做您想做的事,或者可能是阴影插件,在某些情况下是组合。

使用程序集插件,您可以在项目中放置一个带有任何必要设置的清单文件,尽管默认值通常非常好。然后构建完成

mvn assembly:assembly

或者,如果您有更多特殊的事情要处理,可以选择其他目标之一。所有要包含的 JAR 文件都由 Maven 的依赖解析器拾取。如果您使用 shade 插件,它通常是安装目标的一部分,在我现在正在做的一个特定项目中,我会这样做

mvn install
mvn assembly:single

assembly:single 的目标是解决生命周期问题,在本例中是在 Spring 应用程序中。

【讨论】:

【参考方案5】:

ProGuard 不仅可以将你的 JAR 文件打包成一个,还可以优化、清理或混淆你的类文件,使生成的 JAR 文件比之前所有 JAR 文件的总和小得多。

我实际上使用 JRST 工具尝试了 ProGuard,正如您所报告的那样。我试图追踪问题,发现它与 jrst 引用的 ICU4J 库中的a bug 相关。问题是,现在使用的 ICU 版本已经过时了。所以我用 ICU4J 3.2 版替换了icu.jar 文件。现在 ProGuard 发现了一堆关于 JRST 库不一致的其他错误/警告。

我的猜测是 ProGuard 按预期工作,但 jrst 的库并不一致。我不知道除了与它的开发人员交谈之外你还能做些什么,因为他们应该检查和更新项目的依赖关系。

【讨论】:

谢谢!我下载了它并尝试了,但是在这个特定的字段中,它在 icu4j-2.6.1.jar 上被未知的常量字段轰炸了,【参考方案6】:

您可以使用JarJar,它将使用包阴影来确保您的 JAR 文件不会与其他文件冲突。

【讨论】:

【参考方案7】:

(基于 Andrian 的):

<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】:

One-JAR 0.97 刚刚在http://one-jar.sourceforge.net 发布,并且已经扩展了对Spring 和Guice 等框架的支持,这可能会给其他方法带来麻烦。它还处理类加载器反转——其中一些 JAR 文件位于 One-JAR 外部(例如,JDBC 驱动程序可能未捆绑发货)。

One-JAR 是命令行,带有Ant 和Maven 2 个插件。使用“jar”工具构建也很简单。

我还可以推荐 Eclipse Jar Exporter (Runnable),Ference Hechler 在上面写道:他非常出色地提出了一种包装一组 JAR 文件的简单方法。他和我在 One-JAR 上工作,但 Jar Exporter 基于不同的代码库。

【讨论】:

【参考方案9】:

有一个名为 autojar 的工具会扫描您的字节码并使用它找到的类编译一个 .jar 文件,包括引用(导入)的类。

但并不总是适用于 Spring 之类的东西,您可以在其中指定配置中的类名并由框架加载。

【讨论】:

感谢您的指点,似乎这个特定应用程序中的一些 .jar 让我在完成这项工作时有些头疼。【参考方案10】:

或者使用Maven组装插件(mvn assembly:assembly)

【讨论】:

【参考方案11】:

我认为你这里需要的工具是JarSplice:http://ninjacave.com/jarsplice

不需要需要 Ant 或 Maven,有自己的 GUI,使用起来很简单,完全按照你的要求做 --> 它合并了几个 jar 的内容文件合并到一个文件中(请注意它仍然需要添加自己的类加载器)。

【讨论】:

【参考方案12】:

您应该使用 maven 着色插件来做到这一点。我经常使用maven构建独立的jar文件,它非常强大

查看更多:

http://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html

【讨论】:

【参考方案13】:

听起来像 Apache Ant 就是你要找的东西。

【讨论】:

以上是关于将发布合并到一个 JAR 文件中的最简单方法的主要内容,如果未能解决你的问题,请参考以下文章

“樱桃选择合并”的最简单方法

将所有 memcached 密钥转储到文件中的最简单方法是啥?

将原始 .aac 文件包装到 .m4a 容器中的最简单方法是啥

如何使用 gradle 构建源 jar?

spring-boot项目直接读取jar包内文件的最简单方法

将多个源文件合并为一个胖二进制文件的简单方法