使用 Maven 检测依赖冲突

Detecting dependency conflicts with Maven

我有一个 Maven 构建的 Java 应用程序,它引入了许多库。该应用程序在一个 git 存储库中(具有自己的 Maven 构建),每个库都在其自己的 git 存储库中(具有其自己的 Maven 构建)。此外,应用程序和一些库都依赖于番石榴。

应用的pom.xml指定guava版本19.0:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
    </dependency>
</dependencies>

该应用程序还导入了另一个库,称为 library1。 library1 也依赖于番石榴。但是library1的pom.xml指定了更高版本的guava:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
    </dependency>
</dependencies>

构建应用程序时,maven选择了在应用程序级别指定的guava版本。但这导致 library1 失败,因为它需要更高版本的番石榴。

如果我们一直在使用 grade 并尝试指定这种 guava 版本组合,我相信 gradle 会导致构建失败,这可能是正确的做法。

鉴于我们可能有 pom.xml 个版本差异的文件,有没有办法设置 maven 以便它会注意到差异并导致构建失败或显示非常突出的警告关于问题?

您可以在 Maven 中设置 dependencyConvergence 强制规则。此规则要求依赖版本号收敛。

如果一个项目有两个依赖项,A 和 B,它们都依赖于同一个工件 C,如果 A 依赖的 C 版本与 B 依赖的 C 版本不同,则此规则将导致构建失败。

规则可以这样添加。

<project>
  ...
  <build>
    <plugins>
      ...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-enforcer-plugin</artifactId>
        <version>3.0.0-M2</version>
        <executions>
          <execution>
            <id>enforce</id>
            <configuration>
              <rules>
                <dependencyConvergence/>
              </rules>
            </configuration>
            <goals>
              <goal>enforce</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      ...
    </plugins>
  </build>
  ...
</project>

可以找到更多详细信息here

要检测所有传递依赖项,您可以使用 maven-dependency-plugin:

mvn dependency:tree -Dverbose

它将显示您的项目的直接和传递依赖关系。 -Dverbose 选项显示冲突。

[INFO] [dependency:tree]
[INFO] org.apache.maven.plugins:maven-dependency-plugin:maven-plugin:2.0-alpha-5-SNAPSHOT
[INFO] +- org.apache.maven.reporting:maven-reporting-impl:jar:2.0.4:compile
[INFO] |  \- commons-validator:commons-validator:jar:1.2.0:compile
[INFO] |     \- commons-digester:commons-digester:jar:1.6:compile
[INFO] |        \- (commons-collections:commons-collections:jar:2.1:compile - omitted for conflict with 2.0)
[INFO] \- org.apache.maven.doxia:doxia-site-renderer:jar:1.0-alpha-8:compile
[INFO]    \- org.codehaus.plexus:plexus-velocity:jar:1.1.3:compile
[INFO]       \- commons-collections:commons-collections:jar:2.0:compile

同库不同版本的选择:

Dependency mediation - this determines what version of an artifact will be chosen when multiple versions are encountered as dependencies. Maven picks the "nearest definition". That is, it uses the version of the closest dependency to your project in the tree of dependencies. You can always guarantee a version by declaring it explicitly in your project's POM. Note that if two dependency versions are at the same depth in the dependency tree, the first declaration wins.

"nearest definition" means that the version used will be the closest one to your project in the tree of dependencies. For example, if dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A -> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter. You could explicitly add a dependency to D 2.0 in A to force the use of D 2.0.

因此,如果您的某个库无法与其他版本的番石榴一起使用,则意味着您的依赖项不兼容。应该更新它以使用较新的版本。