目前我经历的公司的主要项目管理工具都是maven,maven除了是一个实用的构建工具外,也是一个功能强大的项目管理工具。其管理功能分为信息管理和依赖管理。通过pom.xml文件实现。
信息管理
信息管理主要用于定义当前项目构建的主要信息。
-
单模块项目
对于单个模块项目,其主要管理元素如下:其中project元素为pom.xml的根元素,groupId+artifactId+version三者合一被称为项目的坐标。
-
多模块项目
maven除了可以定义单模块的项目外,还可以通过多个pom.xml文件的配置,将多个模块组织成平行结构或父子结构的多模块项目。由于目前接触比较多的是父子结构的多模块项目,此处主要介绍下该结构下的信息管理配置。
父子结构的项目,父模块下一般并无项目代码,只是一个父pom文件用于将多个子模块、多模块依赖、多模块打包组合在一起。一个典型的父pom管理信息配置如下,其中:
-
packaging值必须为pom,否则项目无法构建;
-
module的值为子模块相对于父pom的相对目录,用于定位子模块。
子模块的pom配置相对复杂,需配置parent元素,用于指定父pom。例如下图,其中:
-
parent包含groupId/artifactId/version/relativePath
-
relativePath表示父pom相对当前pom的项目路径;可不填写,不填时默认值为../pom.xml。该元素用于当子模块构建时,根据该值检查父pom的依赖。
依赖管理
依赖管理用于处理项目模块对库的依赖关系。特别是当一个项目是多模块项目时,通过依赖管理处理依赖冲突变得特别重要。
-
单模块依赖
模块的依赖,也跟项目的信息一样通过groupId+artifactId+version坐标定义,此外还有些其他元素用于配置一些特殊信息,例如下图
其中:
-
type类型默认为jar
-
optional用于标记依赖是否可选
-
exclusions用于排除传递性依赖
-
scope表示依赖范围;
由于maven管理了在不同执行场景下的classpath。主要分为编译classpath、测试classpath(编译和执行测试)和运行classpath。scope元素的类型就决定了该依赖jar包的classpath。具体决定关系如下表所示:
编译classpath |
测试classpath |
运行classpath |
举例 | |
compile(默认) |
√ |
√ |
√ |
|
test |
√ |
JUnit |
||
provided |
√ |
√ |
servlet-api,在编译和测试时需要,但运行时容器已提供,不需重复引入 |
|
runtime |
√ |
√ |
JDBC驱动 |
|
system |
√ |
√ |
maven仓库之外的本地类库文件 使用时必须通过systemPath显式置顶依赖文件路径,应慎用 |
-
多模块-父模块依赖配置
在有父子pom配置的结构下,子模块可以继承父模块的依赖,父pom需通过dependencyManagement元素管理,如下图所示。父pom配置依赖后,子模块需要使用该依赖时,只需配置groupId和artifactId,maven即会去父pom中寻找相关依赖。
-
依赖解析原则
由于不同的模块可以配置不同的依赖,而依赖的库又有自己的依赖,在多层依赖下有可能会产生依赖冲突。因此在maven配置下定义了两条依赖解析原则:
-
路径近者优先;
-
第一声明者优先
例如某项目有各依赖对x构件的依赖关系如下:a-b-c-x1 a-c-x2 a-d-x3 则解析x2。