1、依赖的配置
1.1 坐标
Maven采用坐标来唯一标识一个构件,一组坐标包含以下元素:groupId、artifactId、version、packaging、classifier,其中groupId、artifactId、version是必须的,packaging是可选的,classifier是不能直接定义的。项目构件的名称一般为:artifactId-version[-classifier]. packaging
groupId:定义了当前项目所隶属的实际项目,一般一个公司或组织会有很多的实际项目,而一个实际项目下边又会包含很多的模块;
artifactId:定义了实际项目中的一个模块,一般会将实际项目名称作为artifactId的前缀;
version:定义了当前项目版本;
packaging:定义了Maven项目的打包方式,打包方式不同其构建的生命周期也会不同,默认的打包方式为jar;
classifier:定义了构建输出的一些附属构件,比如,Java文档、源代码等,该元素不能在项目中直接定义,因为附属构件不是由项目直接生成的,而是由附加的插件生成的。
1.2 依赖的配置
<project>
...
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
<type>jar</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>group-c</groupId>
<artifactId>excluded-artifact</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
根元素project下的dependencies可以包含一个或多个dependency元素,用于声明一个或多个依赖,每个dependency元素下可以包含如下元素:
groupId、artifactId、version:构件的基本坐标;
type:依赖的类型,对应于坐标中的packaging元素;
scope:依赖的范围,包括compile(默认)、provided、runtime、test、system、import(仅支持在dependencyManagement元素中依赖pom类型的依赖);
exclusions:用于排除传递性依赖。
1.3 依赖的范围
compile:编译依赖范围。默认的依赖范围,在没有指定时使用;对编译classpath、测试classpath、运行classpath都有效;具有传递性;
provided:已提供依赖范围。使用此依赖范围说明您希望JDK或者容器在运行时提供赖关系,例如,在web项目中使用的servlet-api,应将其设置为provided,因为web容器已提供了此依赖。该依赖范围仅对编译和测试的classpath有效,且不可传递;
test:测试依赖范围。此依赖范围的Maven依赖只对测试classpath有效,典型的依赖就是JUnit,它只在测试代码编译和执行测试的时候才可用;不具有传递性。
runtime:运行时依赖范围,该依赖范围表明该依赖不是编译所必需的,而是执行时所必需的,故此依赖范围只对于测试和运行的classpath有效,具有传递性。
system:系统依赖范围。该依赖范围与classpath的关系,和provided依赖范围完全一致,但是,此依赖不是通过Maven仓库解析的,而是与本机系统绑定的,所以在使用此依赖范围时必须通过systemPath元素显式地指定所依赖文件的路径。不具备传递性。
<dependency>
<groupId>javax.sql</groupId>
<artifactId>jdbc-stdext</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
import:导入依赖范围。该依赖范围不会对三种classpath产生实际的影响,它仅在dependencyManagement中的pom类型的依赖中使用。不具有传递性。
1.4 依赖的传递性
若Project-A依赖Project-B,而Project-B又依赖Project-C,则Project-C就是Project-A的一个传递性依赖。
2、依赖的解析
2.1 依赖的解析机制
<1> 当依赖的范围是system时,Maven会根据systemPath元素配置的路径信息从本地文件系统查找所需要的构件;
<2> 若依赖的范围不是system,则根据依赖的坐标计算仓库的路径,然后从本地仓库查找所需构件,若找到,则说明解析成功;
<3> 若本地仓库中没有找到所需构件,且所依赖构件的版本是正式版,则遍历所有的远程仓库,找到依赖后下载并解析使用;
<4> 若所依赖构件的版本是SNAPSHOT版,则基于更新策略读取所有远程仓库的元数据groupId/artifactId/version/maven-metadata.xml,将其与本地仓库的对应元数据合并后,得到最新的快照版本,然后根据此版本查找本地仓库,或从远程仓库下载。
2.2 依赖调解
Maven会自动解析所有项目的直接依赖和传递性依赖,并且根据相应的规则正确判断每个依赖的范围,对于一些依赖冲突,也能进行调解,以确保任何一个构件只有唯一的版本在依赖中存在。调解的原则如下:
第一原则:路径最近者优先。假设Project-A存在这样的依赖关系:Project-A -> Project-B -> Project-X(1.0),Project-A -> Project-C -> Project-D -> Project-X(2.0),则说明Project-X是Project-A的一个传递性依赖,并且Project-X有两个版本,Project-X(1.0)的路径长度为2,Project-X(2.0)的路径长度为3,此时Maven会解析使用Project-X(1.0);
第二原则:第一声明原则。若依赖路径的长度相等的情况下,在POM中依赖声明的顺序最靠前的那个依赖会被解析使用。