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
spring framework和spring的关系
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中依赖声明的顺序决定了谁会被解析使⽤。顺序最靠前的那个依赖优胜。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。