30

我们有一个大型(>500,000 LOC)Java 系统,它依赖于 40-50 个 OSS 包。系统是用Ant搭建的,目前依赖管理是手动处理的。我正在调查 Ivy 和/或 Maven 以自动化依赖项。去年我们将 Maven 视为构建自动化系统并拒绝了它,因为它需要完全重组我们的系统以匹配 Maven 的架构。现在我正在寻找自动化依赖管理任务。

我已经对 Ivy 进行了一些实验,但遇到了问题。例如,当我将 ActiveMQ 指定为依赖项,并告诉 Ivy 使用 Maven 存储库中的 POM 来指定依赖项时,Ivy 会检索一堆我知道不需要的包(例如 Jetty、Derby 和 Geronimo)使用 ActiveMQ。

如果我在 ivysettings.xml 中设置 usepoms="false",它只会获取 activemq.jar,但这似乎违背了 Ivy 的目的,并将其降级为具有手动构建依赖项规范的简单 jar-fetcher。

这里有一个更大的问题,以前在 Windows 中被称为“DLL Hell”。在某些情况下,两个直接的一级依赖项将指向同一传递依赖项的不同版本(例如 log4j.jar)。类路径中只能有一个 log4j.jar,因此依赖关系解析涉及手动确定哪个版本与我们系统中的所有客户端兼容。

我想这一切都归结为每个包的依赖规范(POM)的质量。在 ActiveMQ 的情况下,没有范围声明,所以任何对 ActiveMQ 的引用都会下载它的所有依赖项,除非我们手动排除我们知道不想要的那些。

在 log4j 的情况下,自动依赖解析将要求 log4j 的所有客户端(依赖于 log4j 的其他包)针对所有先前版本的 log4j 进行验证,并在 POM 中提供兼容 log4j 版本的范围(或列表)。这可能问得太多了。

这是目前的情况,还是我错过了什么?

4

8 回答 8

11

你说的完全正确

我想这一切都归结为每个包的依赖规范(POM)的质量。

我唯一要补充的是查看 POM 或任何其他形式的元数据,作为起点。例如,ActiveMQ 为您提供所有依赖项非常有用,但您可以选择它是否真的适合您的项目。

毕竟,即使考虑到 log4j 版本,您是否有外部依赖项选择版本或选择您知道适合您的版本?


至于如何选择定制依赖项,以下是 Ivy 可以做的事情:

不需要的包

Ivy 检索了一堆包(例如 Jetty、Derby 和 Geronimo),我知道这些包不需要仅使用 ActiveMQ。

这通常是由于应用程序的模块化程度低而发生的。例如,应用程序的某些部分需要 Jetty,但即使您不使用它,您最终也会得到这种传递依赖。

您可能想研究常春藤排除机制

<dependency name="A" rev="1.0">
  <exclude module="B"/>
</dependency>

依赖版本

类路径中只能有一个 log4j.jar,因此依赖关系解析涉及手动确定哪个版本与我们系统中的所有客户端兼容。

也许我误读了这一点,但 Ivy 的冲突解决方案中没有手动元素。有一个默认冲突管理器列表:

  • all:此冲突管理器通过选择所有修订来解决冲突。也称为 NoConflictManager,它确实驱逐任何模块。
  • latest-time:此冲突管理器仅选择“最新”修订,最新被定义为最新的时间。请注意,最新的时间计算成本很高,所以如果可以的话,最好选择最新的版本。
  • latest-revision:此冲突管理器仅选择“最新”修订,最新由修订的字符串比较定义。
  • latest-compatible:此冲突管理器选择冲突中的最新版本,这可能会导致一组兼容的依赖项。这意味着最终这个冲突管理器不允许任何冲突(就像严格的冲突管理器一样),除了它遵循尽力而为的策略来尝试找到一组兼容的模块(根据版本约束);
  • strict:只要发现冲突,此冲突管理器就会抛出异常(即导致构建失败)。

如果需要,您可以提供自己的冲突管理器

于 2009-09-21T18:59:55.837 回答
5

差不多就是这样。maven 依赖系统(Ivy 或多或少遵循)让各个项目为它们的依赖项添加必要的元数据做好工作。大多数没有。

如果你走那条路,预计会花时间设置排除项。

对于推荐 OSGi 的海报,OP 说他不愿意为 Maven 重新构建他的构建系统,我认为他不想重新构建他的应用程序以符合 OSGi。此外,许多符合 OSGi 的 OSS 项目(并且没有您希望的那么多)的元数据与 Maven 中的一样糟糕或更差

于 2009-09-21T18:57:11.570 回答
5

在您列出的依赖项中,以下是optionalactivemq-corepom 中定义的(另请参阅 Maven 书中的相关部分)。

  • org.apache.derby:德比
  • org.apache.geronimo.specs:geronimo-jta_1.0.1B_spec

我没有看到对 Jetty 的直接依赖,因此它可能是从可选依赖项之一中传递的。

在 Maven 中,可选依赖项是自动处理的。本质上,任何声明为可选的依赖项都必须在您的 pom 中重新声明才能使用。从上面链接的文档中:

当确实不可能(无论出于何种原因)将项目拆分为子模块时,使用可选依赖项。这个想法是,某些依赖项仅用于项目中的某些功能,如果不使用该功能,则不需要。理想情况下,这样的功能将被拆分为依赖于核心功能项目的子模块......这个新的子项目将只有非可选依赖项,因为如果您决定使用子项目的功能,您将需要它们。

然而,由于项目不能被拆分(同样,无论出于何种原因),这些依赖项被声明为可选的。如果用户想要使用与可选依赖相关的功能,他们将不得不在自己的项目中重新声明该可选依赖。这不是处理这种情况的最明确的方法,但是可选依赖项和依赖项排除都是权宜之计。

我不确定您是否可以将 Ivy 配置为忽略可选依赖项,但您可以将其配置为排除依赖项。例如:

<dependency name="A" rev="1.0">
  <exclude module="B"/>
</dependency>

我知道这并不完全令人满意。可能 Ivy 确实支持可选依赖项(如果我发现任何东西,我会进一步查看和更新​​),但排除机制至少允许您管理它们。


关于你问题的最后一部分。Maven 将解析 log4j 的依赖版本,如果版本兼容,它将自动选择列出的版本中的“最近”版本。

依赖机制的介绍

  • 依赖中介——这决定了当遇到工件的多个版本时将使用哪个版本的依赖。目前,Maven 2.0 仅支持使用“最近定义”,这意味着它将使用依赖树中与您的项目最接近的依赖版本。您始终可以通过在项目的 POM 中明确声明来保证版本。请注意,如果两个依赖版本在依赖树中的深度相同,则在 Maven 2.0.8 之前没有定义哪个会获胜,但从 Maven 2.0.9 开始,声明中的顺序很重要:第一个声明获胜。

    • “最近的定义”意味着使用的版本将是依赖关系树中最接近您的项目的版本,例如。如果 A、B 和 C 的依赖项定义为 A -> B -> C -> D 2.0 和 A -> E -> D 1.0,则构建 A 时将使用 D 1.0,因为从 A 到 D 的路径通过E 更短。您可以在 A 中显式添加对 D 2.0 的依赖项以强制使用 D 2.0

在版本不兼容的地方,您遇到的问题比依赖解析更大。我相信 Ivy 采用类似的模式,但我不是专家。

于 2009-09-21T19:07:09.773 回答
4

我认为这确实是目前的状况。OSGi和为 java 1.7 提议的新包装系统(已经讨论过这个问题已经得出结论了吗?)试图解决至少依赖于不同版本的库问题,但我没有认为他们现在就能解决您的问题。

于 2009-09-21T18:48:21.903 回答
3

我目前正在使用 Ivy 为多个项目(一些独立的,一些依赖的)管理 120 多个 OSS 和专有库。早在 2005 年(当时 Ivy 还来自 Jayasoft),我决定(或不得不)为每个集成包编写 ivy.xml 文件。

最大的优势是我可以完全控制各种配置。这对某些人来说可能听起来有点矫枉过正,但我​​们的构建系统已经可靠地工作了 4 年多,添加一个新库通常是 5 分钟的工作。

于 2009-09-21T22:47:49.917 回答
2

“这就是现在的情况吗?”

不使用 OSGi。您可能想查看 OSGi 容器和捆绑包。一个包就像一个 jar 文件,但它支持详细说明其版本的元数据,以及它需要的相关包的版本(通过将属性放在 META-INF 文件中)。因此,您的 log4j 包将指示其版本,而依赖包将详细说明它们需要哪些版本的 log4j。

此外,还支持非分层类加载器机制,这样您就可以加载 log4j 的多个版本,并且不同的包可以指定并绑定到这些不同的版本。

Javaworld在这里有很好的介绍。

于 2009-09-21T18:49:16.503 回答
0

存在依赖注入的整个想法——这总是会导致程序需要重组。我一直听到一些关于 GUICE 在这方面做得很好的声音。从部署的角度来看,我只部署了我们构建的 .jar,依赖 .jar 是通过 jnlp 从原始项目中获取的。这背后的构建系统涉及手动跟踪新版本的依赖关系并在构建系统中更新。

于 2009-09-22T06:10:42.607 回答
-5

“这就是现在的状况吗”

是的。

这是开源的权衡。

一个闭源框架(即.Net)将为您解决所有这些问题。

开源解决方案意味着您必须始终解决它(并解决它)。

您也许可以找到一些预先构建的配置,并花钱请人保持这些配置是最新的。例如,您可以选择使用 Red Hat Enterprise Linux。如果你坚持他们所支持的(仅此而已),那么配置就解决了。

但是,很有可能没有打包配置满足您的要求。

于 2009-09-21T18:46:25.693 回答