【问题标题】:Java jar files into a repository (CVS, SVN..)Java jar 文件到存储库(CVS、SVN..)
【发布时间】:2011-06-06 15:33:04
【问题描述】:

为什么将 Java jar 文件提交到存储库(CVS、SVN..)是一个坏主意

【问题讨论】:

  • 您能否澄清一下您是在谈论第三方 jar 还是从您自己的源代码生成的 jar?
  • 两者。从我们拥有的源和第三方/开源 jar 文件生成的 jar 文件。
  • 这可能永远争论不休,我的偏好是包含 jars 而不是使用依赖引擎,因为它们只是为管理一个非常简单的问题引入了另一层复杂性。
  • 无论你做什么,确保当有人签出项目时,他们可以运行你的构建脚本,他们将拥有他们需要的一切,无论你使用像 Ivy 或 Maven 这样的依赖引擎还是只管理自己图书馆。

标签: java jar


【解决方案1】:

所以,您有一个使用一些外部依赖项的项目。这种依赖性是众所周知的。他们都有

  • 一个组(通常是创建它们的组织/锻造)
  • 标识符(他们的名字)
  • 一个版本

在 maven 术语中,这些信息称为工件(您的 Jar)坐标。

我所说的依赖关系要么是内部的(对于 Web 应用程序,它可以是您的服​​务/域层),要么是外部的(log4j、jdbc 驱动程序、Java EE 框架,等等)。事实上,所有这些依赖项(也称为工件)在它们的最低级别都是二进制文件(JAR/WAR/EAR),您的 CVS/SVN/GIT 将无法有效地存储它们。实际上,SCM 使用的假设是版本化内容,即差异操作最有效的内容)只是文本。因此,在存储二进制数据时,它们很少进行存储优化(与仅存储版本差异的文本相反)。

因此,我倾向于建议您使用依赖管理构建系统,例如mavenIvyGradle。使用这样的工具,您将在一个文本(或者可能是 XML)文件中声明所有依赖项(实际上,在此文件中,您将声明依赖项的工件坐标),该文件将位于您的 SCM 中。但是您的依赖项不会在 SCM 中。相反,每个开发者都会将它们下载到自己的开发机器上。

这会将一些网络负载从 SCM 服务器转移到 Internet(带宽通常比内部企业网络更受限制),并提出工件的长期可用性问题。使用企业代理解决了这两个答案(至少在 amven 工作中,但我相信 Ivy 和 gradle 都能够连接到此类工具 - 似乎有人在这个主题上提出了一些问题)使用企业代理,如 NexusArtifactory 和其他人。

这些工具的美妙之处在于,它们在内部网络中提供了所有所需工件的视图,甚至允许您在这些存储库中部署自己的工件,使您的代码共享既简单又独立于源代码(这可能是一个优势)。

总结这个冗长的回复:使用 Ivy/Maven/Gradle 而不是简单的 Ant 构建。这些工具将允许您定义您的依赖项,并完成下载这些依赖项并确保您使用声明的版本的所有工作。

就个人而言,在我发现这些工具的那一天,我对 Java 依赖处理的愿景从噩梦变成了天堂,因为我现在只需要说我使用的是这个工具的这个版本,而 maven(在我的情况下),完成所有后台工作,将其下载并存储在我计算机上的正确位置。

【讨论】:

  • CVS 不能有效地存储二进制文件。然而,SVN(我猜是 Git、Mercury 等)以高效的二进制格式存储所有内容,甚至是文本文件。
  • 默认情况下,Mercurial 不会以有效的方式存储二进制文件。它存储字节,如果文件中的一个字节发生变化,则再次存储该文件的完整副本。查看“largefiles”扩展来处理二进制文件(但它带有权衡)
  • 此外,maven 允许您在处理库时在 Eclipse/intellij 中链接项目,而无需使用类路径来指向项目而不是库。当然,它管理所有的传递依赖并处理可能重叠的 .jar 文件(毕竟,它是一个“依赖管理器”) 版本控制更简单,总的来说,将 .jar 检入源代码控制只是痛苦。
【解决方案2】:

源代码控制系统是为保存文本源代码而设计的。它们可以保存二进制文件,但这并不是它们的真正目的。在某些情况下,将二进制文件置于源代码管理中是有意义的,但通常以不同的方式更好地管理 java 依赖项。

理想的设置是让您在源代码控制之外管理依赖项。您应该能够在源代码之外管理您的依赖项,并且只需从源代码中“指向”所需的依赖项。这有几个优点:

  • 您可以让多个项目依赖于相同的二进制文件,而无需保留每个二进制文件的单独副本。中型项目通常有数百个依赖的二进制文件。这可能会导致大量重复,从而浪费本地和备份资源。
  • 可以在本地环境或公司实体内集中管理二进制文件的版本。
  • 在许多情况下,源代码控制服务器不是本地资源。添加一堆二进制文件会减慢速度,因为它会增加需要通过较慢连接发送的数据量。
  • 如果您要创建战争,可能需要一些 jar 用于开发,但不需要部署,反之亦然。一个好的依赖管理工具可以让您轻松高效地处理这些类型的问题。
  • 如果您依赖来自另一个项目的二进制文件,它可能会经常更改。这意味着您可能会不断地用新版本覆盖二进制文件。由于版本控制会保留每个副本,因此它可能会迅速增长到无法管理的大小 - 特别是如果您有任何类型的持续集成或创建这些二进制文件的自动构建脚本。
  • 依赖管理系统在您如何依赖二进制文件方面提供了一定程度的灵活性。例如,在您的本地机器上,您可能希望依赖最新版本的依赖项,因为它位于您的文件系统上。但是,当您部署应用程序时,您希望将依赖项打包为 jar 并包含在您的文件中。

Maven 的依赖项管理功能为您解决了这些问题,并可以帮助您根据需要查找和检索二进制依赖项。 Ivy 是另一个可以做到这一点的工具,但它是针对 Ant 的。

【讨论】:

  • 嗨,马克,您的前两句话对于 CVS 是正确的,但对于 SVN 则不是(我猜是大多数现代 SCM)。 svnbook.red-bean.com/en/1.5/svn.forcvs.binary-and-trans.html
  • Kevin,我意识到大多数 SCM 都可以保存二进制信息。我只是说它们主要是为存储文本而构建的。您将与 SCM 一起使用的许多工具仅在处理文本文件时才有意义。此外,如果您在 SCM 中存储大型 .jar 文件,并且当您升级到不同版本时它们会发生变化(文件名和内容),那么您的存储库可能会因所有不同版本的二进制文件而变得非常臃肿。在某些情况下,这可能无关紧要,但在其他情况下,它可能会减慢您的操作速度并使备份成为更多问题。
  • 嗨,马克,除了古老的 CVS,SCM 并不是为存储文本而构建的。就存储而言,所有文件都是二进制文件,它们使用高效的二进制差分算法。
  • 获取进入 SCM 的所有代码并将其分为三个部分: 1. 所有主要用于处理文本的代码。 2. 所有主要用于处理二进制文件的代码 3. 所有通用代码并用于两种类型的文件。我仍然认为 1 和 3 中的代码数量将大于 2 和 3 中的代码。这是因为任何 SCM 系统中一些最复杂的部分都在处理组合更改——这是你对二进制不做的事情文件。因此,虽然它们可以很好地处理二进制文件,但这不是它们的主要目的或设计。
  • 我要再补充一点——正确配置的依赖管理系统能够跟踪传递依赖,如果你不包括它们,你通常会在运行时得到 ClassNotFound,而且通常只有当你使用您的产品的某些角落功能不属于您的自动化测试。
【解决方案3】:

将 jar 文件提交到 SCM 的决定通常受所使用的构建工具的影响。如果以传统方式使用 Maven,那么您真的别无选择。但是,如果您的构建系统允许您选择,我认为将您的依赖项与依赖于它们的源代码一起提交到 SCM 是一个好主意。

这适用于与您的项目处于不同发布周期的第三方 jar 和内部 jar。例如,如果您有一个包含常用实用程序类的内部 jar 文件,我会将其提交给每个使用它的项目下的 SCM。

如果使用 CVS,请注意它不能有效地处理二进制文件。 SVN 存储库不区分二进制文件和文本文件。

http://svnbook.red-bean.com/en/1.5/svn.forcvs.binary-and-trans.html

根据马克发布的答案进行更新:

WRT 要点 1:我想说即使是大型项目也很少有数百个依赖项。在任何情况下,磁盘使用(通过在每个使用它的项目中保留一个单独的依赖项副本)不应该是您的主要关注点。与处理 Maven 存储库的复杂性所花费的时间相比,磁盘空间很便宜。在任何情况下,本地 Maven 存储库将消耗比您实际使用的依赖项更多的磁盘空间。

要点 3:Maven 不会为您节省等待网络流量的时间。反之亦然。使用源代码控制中的依赖项,您可以进行检出,然后从一个分支切换到另一个分支。您很少需要再次检查相同的罐子。如果你这样做,它只需要几分钟。 Maven 是一个缓慢的构建工具的主要原因是即使在不需要时它也能进行所有的网络访问。

要点 4:您的观点并不是反对将 jar 存储在 SCM 中的论点,而且 Maven 只有在您学会它之后才会变得容易,并且只有在出现问题时才会有效。然后它变得困难,你的效率提升会很快消失。就效率而言,当事情正常时,Maven 有一个小的优势,而当它们不正常时,它有一个很大的劣势。

要点 5:SVN 等版本控制系统不会为每个文件的每个版本保留单独的副本。它将它们有效地存储为增量。您的 SVN 存储库不太可能增长到“无法管理”的大小。

要点 6:您的观点不是反对存储文件的论点是 SCM。您提到的用例可以通过自定义 Ant 构建轻松处理。

【讨论】:

    【解决方案4】:

    它们是二进制文件:

    • 最好引用源代码,因为这就是您使用 源代码管理 的目的。
    • 系统无法告诉您文件之间的哪些差异
    • 如果它们是从同一存储库中的源编译的,它们会成为合并冲突的来源。
    • 某些系统(例如 SVN)不能很好地处理大型二进制文件。

    换句话说,更好地参考源代码,并调整您的构建脚本以使一切正常。

    【讨论】:

    【解决方案5】:

    因为你可以从源头重建它们。另一方面,如果您正在谈论项目所需的第三方 JAR 文件,那么最好将它们提交到存储库中,以便项目是自包含的。

    【讨论】:

    • 嗯,对于依赖关系,解决方案不在 SCM 中,而是在使用依赖管理工具(如 Ivy 或 Maven)中,以便在 SCM 中定义它们,但在其他地方有有效的 JAR。
    • @Riduidel - 这应该是一个答案
    • @Riduidel - 你能描述一下为什么你认为将罐子存放在别处是个好主意吗?发帖人可能以前见过像你这样的cmets,这促使他提出了他的问题,而这也让我感到困惑。
    • @Anon @Kevin_Stembridge 我回复了这条评论,谢谢你们。
    猜你喜欢
    • 2014-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多