9.4.5. 冲突解决

有很多时候你需要排除一个传递性依赖,比如当你依赖于一个项目,后者又继而依赖于另外一个项目,但你的希望是,要么整个的排除这个传递性依赖,要么用另外一个提供同样功能的依赖来替代这个传递性依赖。Example 9.7, “排除一个传递性依赖”展示的例子中添加了一个对于project-a的依赖,但排除了传递性依赖project-b

Example 9.7. 排除一个传递性依赖

<dependency>
  <groupId>org.sonatype.mavenbook</groupId>
  <artifactId>project-a</artifactId>
  <version>1.0</version>
  <exclusions>
    <exclusion>
      <groupId>org.sonatype.mavenbook</groupId>
      <artifactId>project-b</artifactId>
    </exclusion>
  </exclusions>
</dependency>


通常,你会想要使用另外一个实现来替代一个传递性依赖。比如,如果你正依赖于一个类库,该类库又依赖于Sun JTA API,你会想要替换这个传递性依赖。Hibernate是一个例子。Hibernate依赖于Sun JTA API,而后者在中央Maven仓库中不可用,因为它是不能免费分发的。幸运的是,Apache Gernoimo项目创建了一些可以免费分发的独立实现类库。为了用另外的依赖来替换这个传递性依赖,你需要排除这个传递性以依赖,然后在你的项目中再声明一个依赖。Example 9.8, “排除并替换一个传递性依赖”展示了这样一个替换的样例。

Example 9.8. 排除并替换一个传递性依赖

<dependencies>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate</artifactId>
    <version>3.2.5.ga</version>
    <exclusions>
      <exclusion>
        <groupId>javax.transaction</groupId>
        <artifactId>jta</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>org.apache.geronimo.specs</groupId>
    <artifactId>geronimo-jta_1.1_spec</artifactId>
    <version>1.1</version>
  </dependency>
</dependencies>

Example 9.8, “排除并替换一个传递性依赖”中,没有什么标记说依赖geronimo-jta_1.1_spec是一个替换,它只是正好提供了和原来的JTA依赖一样的API。以下列举了一些你可能想要排除或者替换传递性依赖的情况:

  1. 构建的groupIdartifactId已经更改了,而当前的项目需要一个与传递性依赖不同名称的版本——结果是classpath中出现了同样项目的两份内容。一般来说Maven会捕捉到这种冲突并且使用该项目的一个单独的版本,但是当artifactIdartifactId不一样的时候,Maven就会认为它们是两种不同的类库。

  2. 某个构件没有在你的项目中被使用,而且该传递性依赖没有被标志为可选依赖。在这种情况下,你可能想要排除这种依赖,因为它不是你的系统需要的东西,你要尽量减少应用程序分发时的类库数目。

  3. 一个构件已经在运行时的容器中提供了,因此不应该被包含在你的构件中。该情况的一个例子是,如果一个依赖依赖于如Servlet API的东西,并且你又要确保这样的依赖没有包含在web应用的WEB-INF/lib目录中。

  4. 为了排除一个可能是多个实现的API的依赖。这种情况在Example 9.8, “排除并替换一个传递性依赖”中阐述;有一个Sun API,需要点击许可证,并且需要耗时的手工安装到自定义仓库,对于同样的API有可免费分发版本,在中央Maven仓库中可用(Geronimo's JTA 实现)。