依赖范围
- compile:编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。典型的例子是spring-core,在编译、测试、运行的时候都需要使用该依赖。
- test:测试范围依赖。使用此依赖范围的Maven依赖,只对测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此依赖。典型的例子就是Junit,它只有在编译测试代码及运行测试的时候才需要。
- provided:已提供依赖范围。使用此依赖范围的Maven依赖,只对编译和测试classpath有效,但在运行时无效。典型的例子就是servlet-api,编译和测试的项目的时候需要改依赖,但在运行项目的时候,容器已经提供,就不在需要Maven重复地引入一遍。
- runtime:运行时范围依赖。使用此依赖范围的Maven依赖,只对运行和测试classpath有效,但在编译主代码时无效。典型的例子就是jdbc驱动实现,项目主代码在编译只需要JDK提供的JDBC接口,只有在执行测试和运行项目的时候才需要实现上述接口的具体JDBC驱动。
- system:系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围依赖时必须通过systemPath元素显式的指定依赖文件的路径。由于此依赖不是通过Maven仓库解析的,而且往往与本机系统相绑定,可能早就系统的不可移植,应该谨慎使用。
- import:导入依赖范围。该依赖范围不会对三种classpath产生实际的影响。因为该元素在dependencyManagement元素下才有效(dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它能够约束dependencies下的依赖使用)
依赖范围(Scope) |
对于编译classpath有效 | 对于测试classpath有效 | 对于运行classpath有效 |
---|---|---|---|
compile | Y | Y | Y |
test | - | Y | -- |
provided | Y | Y | -- |
runtime | - | Y | Y |
system | Y | Y | -- |
传递性依赖
如下图,最左边第一行表示第一直接依赖范围,最上面第一行表示第二直接依赖范围,中间交叉单元格则表示传递性依赖范围
compile | test | provided | runtime | |
---|---|---|---|---|
compile |
compile | -- | -- | runtime |
test | test | -- | -- | test |
provided | provided | -- | provided | provided |
runtime | runtime | -- | -- | runtime |
依赖调解
有时候,当传递性依赖造成问题的时候,我们就需要清楚地知道该传递性依赖是从哪条依赖路径引入的。
例如:A-->B-->C--X(1.0),A-->D-->X(2.0)
X是A的传递性依赖,但是两条依赖路径上有两个版本的X,这个时候两个都解析是不对的,那样会造成依赖重复,因为必须选择一个。
Maven依赖调解的第一原则:路径最近者优先。上面例子中X(1.0)的路径长为3,X(2.0)的路径长为2,因此2.0会被解析使用。
如果两个依赖长度一样。
Maven依赖调解的第二原则:第一声明者优先。在依赖长度相同的情况下,在POM中依赖声明的顺序决定了谁会被解析使用,顺序靠前的那个优先被依赖
可选依赖
可选性依赖不会得到传递。
例如:A-->B,B-->X(可选),B-->Y(可选)
由于这里的X和Y依赖是可选的,所以依赖不会被传递。下面声明一个可选性依赖:
<dependency>
<group>mysql</group>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
<optional>true</optional>
</dependency>
当项目中要使用可选性依赖的时候,需要显示声明。
排除依赖
传递性依赖会给项目隐式的映入很多依赖,这极大的简化了项目依赖管理,但是有些时候这种特性会带来很多问题。
例如,当前项目引用了一个第三方依赖,而这个第三方依赖由于某些原因依赖了另一个类库的SNAPSHOT版本,那么这个SNAPSHOT就会成为当前项目的传递性依赖,而SNAPSHOT的不稳定性会直接影响当前项目。另外想替换某个传递性依赖。这个时候就需要排除依赖,如下所示:
<dependencies>
<dependency>
<groupId>com.myapp</groupId>
<artifactId>demo</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>com.a</groupId>
<artifactId>project-a</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.a</groupId>
<artifactId>project-a</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
上面的例子排除了一个依赖project-a,并引用了一个其他版本的project-a。