Maven 依赖解析(冲突)

假设我有四个项目:

  • 项目 A (依赖于 B 和 D)
  • 项目 B (依赖于 D)
  • 项目 C (依赖于 D)
  • 项目 D

在这个场景中,如果我运行项目 A,Maven 将正确地解析对 D 的依赖。如果我理解正确的话,Maven 总是采用最短路径的依赖项。因为 D 是 A 的直接依赖关系,所以它将被使用,而不是在 B 中指定的 D。

但现在假设这种结构:

  • 项目 A (依赖于 B 和 C)
  • 项目 B (依赖于 D)
  • 项目 C (依赖于 D)
  • 项目 D

在这种情况下,解析 D 的路径具有相同的深度。Maven 会有冲突。我知道有可能告诉 Maven 他应该排除依赖项。但我的问题是如何解决这类问题。我的意思是,在现实世界的应用程序中,您有很多依赖项,可能还有很多冲突。

最佳实践解决方案真的是排除东西,还是有其他可能的解决方案?当我突然得到 ClassNotfound 异常时,我发现很难处理,因为一些版本已经更改,这导致 Maven 采用了不同的依赖项。当然,了解这个事实会使我们更容易猜测这个问题是一个依赖冲突。

我用的是 Maven2.1-SNAPSHOT。

81259 次浏览

This is fundamentally not a maven issue, but a java issue. If Project B and Project C needs two incompatible versions of project D, then you can't use them both in Project A.

The Maven way of resolving conflicts like these is unfortunately, as you already know, to choose which ones to exclude.

Using mvn dependency:analyze and mvn dependency:tree helps in finding what conflicts you have.

One possible strategy is to specify for main project, what version of D to use (the newest one f.g.). However, if library D is not backward-compatible, you have a problem as stated by kukudas - it's impossible to use both libaries in your project.

In such situation there may be necessary to use either B or C in older version, so that both would depend on compatibile versions of D.

The maven way of resolving situations like this is to include a <dependencyManagement> section in your project's root pom, where you specify which version of which library will be used.

EDIT:

<dependencyManagement>
<dependencies>
<dependency>
<groupId>foo</groupId>
<artifactId>bar</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>

Now no matter which version of library foo:bar is requested by a dependency, version 1.2.3 will always be used for this project and all sub-projects.

Reference:

Maven can handle both situations without any conflict. Conflicts will exist when two versions of a transitive dependency are required. The ClassNotFoundException you describe results from the app (or a dependency) attempting to use a class not available in the version of the conflicted dependency that actually gets used. There are multiple ways to fix the problem.

  1. Update the versions of the libraries you are using that depend on the conflicted dependency, so that they all depend on the same version version of that dependency
  2. Declare the conflicted dependency as a direct dependency of your project with the version you want to be included (in the example, the one with the missing class included in it)
  3. Specify which version of the conflicted dependency that transitive dependencies should use, via the <dependencyManagement> section of the POM
  4. Explicitly exclude the unwanted versions of the conflicted dependency from being included with the dependencies that rely on them using an <exclusion>

You can enforce consistent dependencies in whole project with rule Dependency Convergence.

 <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<id>enforce</id>
<configuration>
<rules>
<DependencyConvergence/>
</rules>
</configuration>
<goals>
<goal>enforce</goal>
</goals>
</execution>
</executions>
</plugin>