在<dependencymanagement>部分声明依赖,即使依赖项没有在任何地方使用?</dependencymanagement>

时间:2009-05-28 15:47:06

标签: java maven-2 dependencies

我们正在使用maven 2.1.0。我有多个完全独立的模块,但仍然有许多常见的依赖项。像log4J,但有些模块不需要它。我想知道在<dependencyManagement>部分的一个父文件中声明所有公共依赖项是否是一个好主意,还是有更好的方法来解决这个问题?

关于<dependencyManagement>的后续问题。如果我在父项的<dependencyManagement>部分中声明Log4J并且子项目不使用它,那么它是否会被包括在内?

6 个答案:

答案 0 :(得分:33)

如果您有父项目,则可以在父pom的dependencyManagement部分中声明所有依赖项及其版本。这个意味着所有项目都将使用所有这些依赖项,这意味着如果项目确实声明了依赖项,它将继承配置,因此它只需要声明依赖项的groupId和artifactId 。您甚至可以在父级的dependencyManagement中声明子项目而不引入循环。

请注意,您也可以通过在pluginManagement部分中声明插件来实现与插件类似的操作。这意味着声明该插件的任何子代都将继承该配置。

例如,如果你有4个项目,核心 ui utils ,你可以在父级中声明所有外部依赖项和内部项目版本。然后子项目继承它们声明的任何依赖项的配置。如果所有模块都具有相同的版本,则甚至可以将这些模块声明为父级中的属性。

示例父母如下:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>name.seller.rich</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>1.4</version>
      </dependency>
      <dependency>
        <groupId>name.seller.rich</groupId>
        <artifactId>ui</artifactId>
      <version>${project.version}</version>
      </dependency>
      <dependency>
        <groupId>name.seller.rich</groupId>
        <artifactId>core</artifactId>
        <version>${project.version}</version>
      </dependency>
      <dependency>
        <groupId>name.seller.rich</groupId>
        <artifactId>utils</artifactId>
        <version>${project.version}</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <modules>
    <module>utils</module>
    <module>core</module>
    <module>ui</module>
  </modules>
</project>

utils,core和ui项目继承了所有相关版本。 utils的:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>name.seller.rich</groupId>
  <artifactId>utils</artifactId>
  <!--note version not declared as it is inherited-->
  <parent>
    <artifactId>parent</artifactId>
    <groupId>name.seller.rich</groupId>
    <version>1.0.0</version>
  </parent>
  <dependencies>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
    </dependency>
  </dependencies>
</project>

核心:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>name.seller.rich</groupId>
<artifactId>core</artifactId>
<parent>
  <artifactId>parent</artifactId>
  <groupId>name.seller.rich</groupId>
  <version>1.0.0</version>
</parent>
<dependencies>
  <dependency>
    <groupId>name.seller.rich</groupId>
    <artifactId>utils</artifactId>
  </dependency>
</dependencies>

UI:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>name.seller.rich</groupId>
  <artifactId>ui</artifactId>
  <parent>
    <artifactId>parent</artifactId>
    <groupId>name.seller.rich</groupId>
    <version>1.0.0</version>
  </parent>
  <dependencies>
    <dependency>
      <groupId>name.seller.rich</groupId>
      <artifactId>core</artifactId>
    </dependency>
  </dependencies>
</project>

答案 1 :(得分:16)

我写了一份best practices的清单。这是最重要的。

  • 始终使用maven-enforcer-plugin
    • 强制执行dependency convergence
      • 否则你可能依赖于两个不同的jar,它们都依赖于log4j。在编译时使用哪一个取决于您不应该记住的一组规则。它们都可以(!)导出为传递依赖。
    • 需要plugin versions(适用于所有插件,甚至是内置插件)
      • 在父pom中的pluginManagement中定义它们以定义版本
      • 否则新版本的maven-surefire-plugin可能会破坏您的构建
  • 使用父pom中的dependencyManagement在所有模块中一致地使用版本
  • 定期运行mvn dependency:analyze
    • 您可能会在编译时直接依赖传递依赖关系。如果是这样,使用您需要的版本将其添加到您的pom非常重要。这与enforcer插件很好地配合使用。
    • 您可能声明了不使用的额外依赖项。这在100%的情况下无法正常工作,特别是对于设计为具有可选部分的库(即,slf4j-api被正确检测到,但slf4j-log4j12失败)。

答案 2 :(得分:8)

每个模块都应该有自己的POM,并声明自己的依赖关系。这不仅跟踪外部依赖关系,还跟踪内部依赖关系。

当您使用Maven构建项目时,它会对整个项目进行排序。因此,如果许多模块(可能全部)依赖于log4j,那么它将只包含一次。如果您的模块依赖于不同版本的log4j,则存在一些问题,但这种方法通常可以正常工作。

(如果有超过1-2个开发人员一起工作)设置内部存储库(如Artifactory)并在内部使用它也很有用。这使得处理不在公共存储库中的库变得更容易(只需将其添加到您的内部存储库!)并且您还可以使用构建工具来推送您自己的代码的构建,以便其他人可以使用这些模块而无需检出代码(在大型项目中有用)

答案 3 :(得分:1)

  

关于的后续问题。如果我在父项的部分中声明Log4J并且子项目不使用它,那么它是否会被包括在内?

没有。依赖管理只设置默认版本和可能的范围(我已经看到这两个看起来都是继承的,似乎没有继承,所以你需要自己查看这个)。要在子模块中包含依赖项,您需要将其声明为模块的依赖项并省略version元素。您可以覆盖子模块中的默认值,只需在子模块的POM的dependency元素中包含版本号。

  

我有多个完全独立的模块,但仍然有很多共同的依赖。

在这种情况下,是和否。

对于作为统一项目一起构建,版本化和部署的模块,例如组成单个Web应用程序的模块,绝对是肯定的。当您决定转移到新版本的依赖项时,您希望减轻自己在多个POM中更改版本的麻烦。当您需要排除某些传递依赖项时,它还可以节省您的工作量。如果您在该部分中使用其排除声明依赖项,则不必在多个POM中维护排除项。

对于不直接相关但在公司内部的单个团队中构建的模块,您可能需要考虑为常用库声明默认版本,例如测试实用程序,日志实用程序等,以使团队使用标准您已定义为最佳实践的一部分的工具版本。请记住,当您标准化一组新的公共库时,您总是可以增加超级POM的版本。您在标准化库和工具之间划清界限,项目特定的库和工具由您决定,但您的团队应该很容易找到。

答案 4 :(得分:1)

我们为所有项目使用具有dependencyManagement块的单个公共父级。当我们将更多项目移动到maven时,这开始崩溃 - 如果项目需要不同的版本,那么我们必须将其声明为所有子项的依赖项,或者明确定义每个相关子项的版本。

我们正在尝试一种模型,我们将dependencyManagement从我们的普通父级拆分出来,然后将我们的公司dependencyManagement pom导入顶层项目pom。这允许我们有选择地定义覆盖公司默认值的项目默认值。

以下是原始方案:

A   defines version 1.0 of foo.jar as the corporate default
B   child of A
C1, C2, C3  children of B
D1, D2, D3 children of C1, C2, C3 respectively

如果D1和D2需要foo.jar的1.1版本,那么我们的选择是:

  1. 声明foo.jar版本1.1作为B中的依赖项,使得看起来C1,C2,C3和D3也依赖于版本1.1
  2. 声明foo.jar版本1.1作为D1和D2中的依赖项,将依赖项声明移动到项目层次结构更深处的多个位置。
  3. 以下是我们正在尝试的内容:

    A   defines version 1.0 of foo.jar as the corporate default
    B   dependencyManagement: imports A, declares a default of foo.jar version 1.1
    C1, C2, C3  children of B
    D1, D2, D3 children of C1, C2, C3 respectively
    

    现在D1和D2只是声明对foo.jar的依赖,并从B的dependencyManagement块中获取版本1.1。

答案 5 :(得分:0)

在多模块项目中,我将任何公共依赖项放在父pom.xml的元素中。如果模块与同一个项目无关,我不确定这是否是最佳实践。