Java JAR包含自己的依赖项是正确还是不正确?

时间:2012-09-30 14:41:28

标签: java ant jar classpath manifest.mf

我想这是一个由两部分组成的问题。我正在尝试编写自己的Ant任务(MyFirstTask),可以在其他项目的build.xml构建文件中使用。为此,我需要在自己的JAR中编译和打包我的Ant任务。因为我编写的这个Ant任务相当复杂,所以它有大约20个依赖项(其他JAR文件),例如使用XStream进行OX映射,使用Guice进行DI等等。

我目前正在MyFirstTask项目中的package文件中编写build.xml任务(将打包myfirsttask.jar的构建文件,这是可重用的Ant任务。)

我突然意识到我并不完全理解Java JAR的意图。是不是JAR应该包含依赖项,并将它留给运行时配置(应用程序容器,运行时环境等)来为它提供所需的依赖项?我会假设如果是这种情况,可执行JAR是规则的例外,是吗?

或者,Java JAR的意图还包括它们的依赖项吗?

无论哪种方式,我都不想强迫我的用户将25个以上的JAR复制到他们的Ant库中;那太残忍了。我喜欢WAR文件的设置方式,其中依赖关系的类路径在classes/目录下定义。

我想,最终,我希望我的JAR结构看起来像:

myfirsttask.jar/
    com/  --> the root package of my compiled binaries
    config/  --> config files, XML, XSD, etc.
    classes/  --> all dependencies, guice-3.0.jar, xstream-1.4.3.jar, etc.
    META-INF/
        MANIFEST.MF

假设为了完成这个(并让运行时类路径也查看classes/目录),我需要以某种方式修改MANIFEST.MF(我知道有一个名为ClassPath的清单属性,我相信?)。我只是把所有事情放在一起很困难,并且对于JAR开始的意图有一个迫在眉睫的问题。

有人可以确认Oracle是否打算让JAR包含其依赖项?而且,无论哪种方式,我必须在清单(或其他任何地方)中做什么,以确保在运行时,类路径可以找到存储在classes/目录下的依赖项?提前谢谢!

5 个答案:

答案 0 :(得分:3)

意图(AFAIU)用于JAR文件的行为类似于本机代码共享对象文件(在Unix上为.so,在Windows上为.dll)。通常,应用程序将安装多个共享对象文件作为兄弟,以及用于启动它们的可执行文件。

可执行JAR更像是一个独立的可执行文件,因此更常见的是包含所有依赖项(类似于静态链接的本机代码可执行文件直接包含其所有依赖对象的方式)。

不幸的是,默认的ClassLoader无法从嵌套的JAR加载类。可以编写一个ClassLoader。或者你可以使用其他人写的。从您对问题的描述来看,Jar Jar Links听起来就像您正在寻找的那样。

答案 1 :(得分:3)

术语“JAR文件”至少可以表示两件事,或者更确切地说,其含义至少有两个方面。最基本的,它意味着一种容器格式:基本上是一个带有META-INF目录的ZIP文件。更精确地说,它意味着这个容器用作打包类文件的方法。

在作为容器的意义上,对内容没有意图;该文件可以包含类文件,其他JAR(在任何意义上!)等。但从代码的打包的角度来看,我认为JAR文件的意图是他们不包含任何依赖。

如果您已阅读JAR File Specification,您会发现存在类文件存储的几种暗示,但没有关于存储其他JAR文件的暗示。相应地,如果你看一下JRE中JAR文件类加载器的实现,它就无法对嵌套的JAR做任何有用的事情。

此外,JAR规范详细说明了处理非嵌套依赖项的机制:the Class-Path attribute。这使得JAR文件可以对文件系统中的其他JAR文件进行相对引用。

现在,包装意义上的JAR文件并不是容器内JAR文件的唯一用途。 WAR,EAR和RAR文件(以及更多文件)都是用于特定目的的JAR文件。每个 都能够包含其他JAR:WAR可以包含包装内的JAR文件,EAR可以包含这些JAR文件。然而,那些与包装感知的JAR文件完全不同的野兽。值得注意的是,需要使用不在Java标准库中的特殊类加载器来使用它们。

WAR等可以将许多JAR文件收集在一起的方式确实非常有用,而且在Java EE之外的Java中没有通用的机制是非常遗憾的。拥有一个简单地捆绑一些JAR的“应用程序存档”或“元存档”格式会很棒。

所以,你留下了这个用户需要25个JAR才能使用你的插件的问题。你有两个选择。

首先,你接受了痛苦,并将你的插件分发为一个装满JAR的拉链,用户必须解压缩。

其次,你加入21世纪,并使用自动处理依赖关系的构建工具和分发机制:在实践中,这意味着使用Gradle,或Maven,或与Ivy一起使用的其他工具(如Ant),从Maven Central获取依赖关系,然后释放您的代码以及列出这些依赖关系的POM文件。然后,用户可以下载您的JAR和POM,并拥有自己的构建工具来获取依赖项。

如果你选择了第二条路线,为了不使用自动依赖关系管理的用户的利益,也可以谨慎地发布依赖关系的zip。

答案 2 :(得分:3)

  

Java JAR包含自己的依赖项是正确还是不正确?

在某些情况下,JAR文件包含它自己是正确的 依赖。如果您想支持不使用现代的用户 依赖关系管理,您可能希望提供包含Ant的JAR文件 任务代码以及所有依赖项。功能更强大,更灵活,更模块化 方法是将版本化的JAR文件发布到Maven repository 只包含您的项目代码。

1)包含项目代码和所有依赖项的JAR文件

赞成

构建JAR

的Ant目标示例
<target name="jar" depends="compile"
    description="Creates a standalone JAR of all class files and dependencies.">
  <jar destfile="${my.ant.task.jar.file}" update="true">
    <fileset dir="${build.classes.dir}" />
    <zipfileset src="${lib.dir}/javax.inject.jar" />
    <zipfileset src="${lib.dir}/guice-3.0.jar" />
    <zipfileset src="${lib.dir}/guice-multibindings-3.0.jar" />
    <zipfileset src="${lib.dir}/guice-assistedinject-3.0.jar" />
  </jar>
</target>

缺点

  • 如果Ant任务的最终用户已经拥有部分或全部依赖项 包含在他们的项目中,然后他们将最终得到冗余的副本 依赖
  • JAR文件可能非常大

2)仅包含发布到Maven Repository

的项目代码的JAR文件

赞成

  • 用户可以获取您已发布到的任何版本的Ant任务 Maven repository,可以更灵活地发布新内容 任务的版本,同时允许现有用户继续使用之前的版本 版本以避免可能的回归
  • 避免公共依赖项的重复副本(除非不同版本的依赖项导致错误)
  • JAR文件很小

缺点

需要了解以下内容:


作为参考,Java™教程提供了JAR文件的一个很好的摘要。

Lesson: Packaging Programs in JAR Files

  

Java™Archive(JAR)文件格式允许您捆绑多个文件   到一个档案文件。 通常,JAR文件包含类文件和   与......相关的辅助资源 应用程序

     

JAR文件格式提供了许多好处:

     
      
  • 安全性:您可以对JAR文件的内容进行数字签名......
  •   
  • 减少下载时间:如果您的小程序捆绑在JAR中......
  •   
  • 压缩:JAR格式允许您压缩文件以提高效率   存储
  •   
  • 扩展包装:扩展框架提供了一种方法   您可以向Java核心平台和JAR文件添加功能   format定义扩展包装......
  •   
  • 包装密封:存储在JAR文件中的包可以选择密封   包可以强制实现版本一致性。密封包装内的包装   JAR文件意味着必须在该包中找到该包中定义的所有类   相同的JAR文件。
  •   
  • 包版本控制:JAR文件可以保存有关其包含的文件的数据,   例如供应商和版本信息。
  •   
  • 可移植性:处理JAR文件的机制是标准的一部分   Java平台的核心API。
  •   

答案 3 :(得分:1)

“Jar Jar Links”仅适用于独立应用程序。但不是Ant。 如果您的项目具有相同的依赖项,并且稍后将它们升级到更新版本,例如xstream - * .jar,则会出现冲突,并且可能会拾取错误的版本。在最坏的情况下会有MethodNotFoundException。这就是为什么在一个jar中包含依赖项是一种不好的做法。

“我不想强迫我的用户复制粘贴25个以上的JAR”会出现什么问题?

这是最简单的解决方案。最好的,因为你将来会避免出现问题。

现在,当您看到Ant的不便之处时,您可能希望将其与Gradle进行比较。使用Gradle,您可以获得与Ant类似的任务,并且您不需要提供任何依赖项jar。您的所有依赖项将解决Gradle。和Ant一样,你仍然可以创建你的任务。

答案 4 :(得分:0)

一些Java应用程序供应商使用以下场景来分发依赖于其他jar的应用程序,它提醒静态链接。在构建jar的阶段,所有依赖项(也是jar)都被解压缩。在构建最终jar时,它们包括新编译的类和从依赖项中提取的类。

可能的问题:

  1. 应用程序无法重用这些库,因为它们包含在应用程序中。通常的静态链接问题。
  2. 必须尊重重新包装的图书馆的许可证。通常可以重新打包它们,但有时必须额外注意他们的许可证文件,这些文件可能恰好在他们的罐子里。
  3. AFAIK不可能在jar中放入jar或者无法为它们指定类路径。因此重新包装程序。