如何在一个不可执行的jar中包含所有依赖的jar?

时间:2012-12-29 15:32:14

标签: java jar classpath manifest onejar

我陷入了一个非常普遍的问题。

我将我的jar(对第三方供应商有很多依赖)插入到应用程序服务器lib目录中。如果我只是将我的jar及其依赖项复制到服务器lib中,那么服务器类路径会变长,因此服务器无法工作。因此,我想将此Jar与其所有依赖项打包在一个jar中,以便服务器的类路径不会变得太长。我在各种论坛上发现有一个实用工具,即OneJar。但是这个实用程序适用于可执行jar。在我的情况下,我的最后一个jar将不可执行。

此外,我尝试了ANT提供的ZIPFileSetGroup实用程序,但这会导致Manifest文件出现安全问题。

请帮助我解决这个问题?

谢谢!

3 个答案:

答案 0 :(得分:2)

如果您使用Maven进行构建,则可以使用maven依赖项插件并使用复制依赖性任务。它会在创建jar文件时将所有依赖项复制到您的jar文件中。

如果手动将jar文件添加到jar文件中,则需要确保jar文件中包含Manifest.mf文件,并指定其中的主类和类路径。

Manifest-Version: 1.0
Main-Class: com.mypackage.MainClass
Class-Path: my.jar log4j.jar

另一种选择可能是构建一个.ear文件,通常是当他们用特定的jar文件打包时,你会看到企业应用程序或.war文件。听起来你正在使用服务器,因此其中一种格式可能更适合你。

答案 1 :(得分:0)

在ANT中的jar任务中使用zipgroupfileset是最简单的方法。

<jar destfile="MyApplication.jar" filesetmanifest="mergewithoutmain">
  <zipgroupfileset dir="lib" includes="*.jar" /> 
  <!-- other options -->
  <manifest>
    <attribute name="Main-Class" value="Main.MainClass" />
  </manifest>
</jar>

请注意,设置为mergewithoutmain的 filesetmanifest 标志会合并除清单的主要部分之外的所有内容。

签名的jar导致 SecurityException 需要手动处理。如果任何与签名jar相关联的类验证jar上的签名作为一个整体,那么那些将在运行时失败。针对特定文件的摘要签名将毫无问题地添加到清单中。由于问题是你的类路径变得太大,你可能无法将所有的jar包装到一个jar中,但是将大部分jar合并在一起使得CLASSPATH可以管理。

还有:http://code.google.com/p/jarjar/

使用所有相关jar创建目标目录。接下来将10个罐子放入一个临时目录中,并继续以10个批次移动罐子,每次尝试从该组中创建单个罐子。当您获得安全性异常时,您可以隔离导致问题的原因。尝试分而治之的方法。如果你有300个罐子,那么只需要做30次。

答案 2 :(得分:0)

当你说

  

子进程从server / lib目录中获取类路径

这是一个由您控制的过程吗?如果父进程要将类路径指定为

server/lib/*

(即文字*)然后目标java进程将枚举lib目录本身的jar文件 - 它们不需要在类路径中命名。< / p>

但是如果父进程明确枚举server/lib/*.jar以构建-cp值,那么您可以利用JAR清单中的Class-Path即使JAR生效也会生效的事实不是“可执行的”。您可以使用这样的节来创建仅清单的JAR文件

<!-- location of your 300 dependency JAR files, file1.jar ... file300.jar -->
<property name="lib.dir" location="lib" />
<fileset id="dependencies" dir="${lib.dir}" includes="*.jar" />

<pathconvert property="manifest.classpath" dirsep="/" pathsep=" "
             refid="dependencies">
  <map from="${lib.dir}" to="myapp" />
</pathconvert>

<jar destfile="myapp-manifest.jar">
  <manifest>
    <attribute name="Class-Path" value="${manifest.classpath}" />
  </manifest>
</jar>

这将生成一个名为myapp-manifest.jar的JAR文件,其清单包含

Class-Path: myapp/file1.jar myapp/file2.jar ... myapp/file300.jar

您将此文件放入server/lib,将300个依赖项放入新目录server/lib/myapp。现在生成的-cp将只包含一个文件(myapp-manifest.jar),但生成的java进程将拥有所有300 myapp个JAR文件。