Maven
的聚合特性能够把项目的各个模块聚合在一起构建,而继承特性则能够帮助抽取各模块相同的依赖和插件等配置,在简化POM
的同时,还能促进各个模块配置的一致性。
5.1 聚合
Maven
聚合也称多模块,能够一次构建多个模块。聚合模块本身是一个Maven
项目,所以也有自己的POM
文件,该POM
文件的packaging
为pom
,并且含有<modules>
和<module>
元素,如:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wangdh</groupId>
<artifactId>springboot.demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>springboot-mybatis</module>
<module>springboot-web</module>
<module>springboot-quickstart</module>
</modules>
</project>
这里每个module
的值都是一个当前POM
的相对目录,一般而言,为了方便快速定位内容,模块所处的目录名称应该与其artifactId
一致,不过这不是Maven
的要求。
因此,聚合模块与其他模块的目录结构并非一定要父子关系,通过修改module
的值,也能更改为平级关系:
<module>../springboot-quickstart</module>
Maven
首先会解析聚合模块的POM
,分析要构建的模块,并计算出一个反应堆构建顺序,然后根据这个顺序依次构建各个模块。反应堆包含了模块之间继承和依赖的关系。模块间的依赖关系会将反应堆构成一个有向非循环图。
5.2 继承
继承解决的是对重复依赖和插件配置的抽取。通过定义一个父模块,将其他模块相同的配置抽离到父模块中,然后继承父模块,并且父模块也是一个Maven
项目,其POM
文件的packaging
为pom
。
子模块需要增加<parent>
元素配置:
<parent>
<artifactId>springboot.demo</artifactId>
<groupId>com.wangdh</groupId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
relativePath
定义了父模块POM
文件的位置。默认值为../pom.xml
,Maven
默认父POM
在上一层目录下。
POM
文件可被继承的元素有:
groupId:项目组ID,项目坐标的核心元素
version:项目版本,项目坐标的核心元素
description:项目的描述信息
organization:项目所在组织机构信息
inceptionYear:项目的创始年份
url:项目的URL地址
developers:项目的开发者信息
contributors:项目的贡献者信息
distributionManagement:项目的部署配置
issueManagement:项目的缺陷跟着系统信息
ciManagement:项目的持续集成系统信息
scm:项目的版本控制系统信息
mailingLists:项目的邮件列表信息
properties:自定义的Maven属性
dependencies:项目的依赖配置
dependencyManagement:项目的依赖管理配置
repositories:项目的仓库配置
build:项目的源码目录配置、输出目录配置、插件配置、插件配置管理等
reporting:项目的报告输出目录配置、报告插件配置等
5.3 聚合与继承比较
对于Maven
聚合,聚合模块知道他聚合了哪些模块,但是被聚合模块不知道它自己被谁聚合了;
对于Maven
继承,子模块知道自己的父模块是谁,但父模块不知道自己有多少子模块。
在实际使用过程中聚合模块和父模块是同一个模块。
5.4 依赖管理
子模块继承父模块时,也会继承父模块的依赖配置,假设添加一个util
的子模块,该模块只提供一些简单的帮助工具,与springframework
完全无关,难道也让它依赖spring-core
、spring-beans
、spring-context
么?这显然是不合理的。
Maven
提供的dependencyManagement
元素既能让子模块继承父模块的依赖配置,又能保证子模块依赖使用的灵活性。在dependencyManagement
元素下声明的依赖不会引入实际的依赖,不过它能够约束dependencies
下的依赖使用。
在父POM
使用dependencyManagement
声明的依赖能够统一项目范围中依赖的版本,在子模块使用依赖的时候就不需要版本了,只需要简单的配置groupId
和artifactId
就能获得对应的依赖信息,从而引进正确的依赖。
如果子模块不声明依赖的使用,即使该依赖已经在父POM
的dependencyManagement
中声明了,也不会产生实际的效果。
如,在父POM
定义如下dependencyManagement
:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
在子模块使用时,只需要:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
对于子模块而言,可以按需添加依赖,对于整个项目而言,可以规范对依赖的版本号管理。