Maven依赖范围Scope及传递性依赖

来源《Maven实战》


<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

依赖范围就是用来控制依赖与三种classpath(编译,测试,运行)的关系,maven有以下几种依赖范围:

compile:编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的maven依赖,对于编译,测试,运行三种classpath都有效。典型的例子是spring-core,在编译,测试,运行的时候都需要使用该依赖。

test:测试依赖范围。使用此依赖范围的maven依赖,只对于测试classpath有效,在编译主代码或运行项目的时候无法使用此类依赖。典型的例子就是junit,它只有在编译测试代码及运行测试的时候才需要。

provided:已提供依赖范围。使用此依赖范围的maven依赖对于编译和测试classpath有效,在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行的时候容器已经提供,就不需要重复引入了。

runtime:运行时依赖范围。使用此依赖范围的maven依赖对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC的驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。

system:系统依赖范围。该范围与三种classpath的关系和provider依赖范围完全一致。但是使用system范围的依赖时必须通过systemPath元素显示地指定依赖文件的路径。由于此依赖不是通过maven仓库解析而且与本机系统绑定,可能造成构建的不可移植因此应该谨慎使用。systemPath元素可以引用环境变量,如下:

<dependency>
  <groupId>javax.sql</groupId>
  <artifactId>jdbc-stdext</artifact>
  <vesion>2.0</version>
  <scope>system</scope>
  <systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>

import: 导入依赖范围。该依赖范围不会对三种classpath产生实际的影响

依赖范围与classpath的关系如下:

依赖范围(scope) 对于编译classpath有效 对于测试classpath有效 对于运行时classpath有效 例子
compile Y Y Y spring-core
test - Y - JUnit
provided Y Y - servlet-api
runtime - Y Y JDBC实现
system Y Y - 本地的,maven仓库之外的类库文件

传递性依赖

maven引入的传递性依赖机制,一方面大大简化和方便了依赖声明,另一方面,大部分情况下我们只需要关心项目的直接依赖是什么,而不用考虑这些直接依赖会引入什么传递性依赖。但有时候,当传递性依赖造成问题的时候,我们就需要清楚地知道该传递性依赖是从哪条依赖路径引入的。

例如,项目A有这样的依赖关系 : A-->B-->C-->X(1.0)、A-->D-->X(2.0),X是A的传递性依赖,但是两条依赖路径上有两个版 本的X,那么哪个X会被maven解析使用呢?两个版本都被解析显然是不对的,因为那会造成依赖重复,因此必须选择一个。maven依赖调解的第一原则:路径最近者优先。该例中X(1.0)的路径长度为3,而X(2.0)的路径长度为2,因此X(2.0)会被解析使用。

依赖调解第一原则不能解决所有问题,比如这样的依赖关系:A-->B-->Y(1.0),A-->C-->Y(2.0),Y(1.0)和Y(2.0)的依赖路径长度是一样的,都为2。那么到底谁会被解析使用呢?在maven2.0.8及之前的版本中,这是不确定的,但是maven2.0.9开始,为了尽可能避免构建的不确定性,maven定义了依赖调解的第二原则:第一声明者优先。在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用。顺序最靠前的那个依赖优胜。

原文地址:https://www.cnblogs.com/sulishihupan/p/15723396.html