五、聚合与继承
好久没有更新了,在这里给大家说声抱歉,实在是因为最近加班忙成狗,还有一个原因是我想把《maven
实战》这本书剩下的最后几个章节看完在统一做笔记,所以......,好了闲话少许,现在开始我们今天的聚合与继承章节的知识要点回顾
maven
的聚合特性能够把项目的各个模块都聚合在一起构建,而maven
的继承特性则能够帮助抽取各个模块相同的依赖和插件等配置,从而让项目像OPPO
那样从这一刻更清晰
聚合
聚合的目的是为了实现多个模块同时构建,为了配置聚合,我们需要创建独立的模块,为模块编写pom.xml
作为聚合模块
<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.zheng</groupId>
<artifactId>account-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>parent project name</name>
<modules>
<module>module1-artifactId</module>
<module>module2-artifactId</module>
</modules>
</project>
该项目只需要提供上面的pom.xml
配置文件即可,其他src
也不需要,这里的packaging
必须为pom
,否则无法构建
为了方便构建,通常将聚合模块作为项目目录的最顶层,其他被聚合的子模块作为项目目录的子目录存在
maven
在编译时会根据pom.xml
中配置的modules
得出一个反应堆构建顺序,并按照这个顺序编译项目模块
建议我们在创建项目的时候为项目模块提供一个合理的name
,因为构建的结果中是通过各个模块中配置的name
来标识每一个项目模块的构件状态的
如下所示,是对一个account-parent
项目的构件结果:
继承
继承目的是为了将一些公共的配置抽取出来,方便其他模块共用,为了实现模块继承,需要以下几步:
- 创建一个新的项目模块,并配置其pom.xml
<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.zheng</groupId>
<artifactId>account-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>parent project name</name>
</project>
跟聚合一样,父模块中的packaging也必须要求是pom
- 编写其他子模块引用父模块
<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>
<parent>
<groupId>com.zheng</groupId>
<artifactId>account-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../account-parent/pom.xml</relativePath>
</parent>
<groupId>com.zheng</groupId>
<artifactId>account-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>parent project name</name>
</project>
上面通过parent
加入父模块在maven
仓库中的坐标来引用maven
通过relativePath
相对路径的方式指定了父模块基于当前子模块的位置,maven
在构建子模块的时候就不会要求父模块一定要先于安装到本地仓库,因为通过该标签指定的相对路径已经可以明确指定到父模块,当然如果本地仓库和relativePath
所提供的路径找不到父模块,那么构建将会失败
可继承的pom元素
groupId
: 项目组id,项目坐标核心元素
version
: 项目版本,项目坐标核心元素
description
: 项目描述信息
organization
: 项目组织信息
inceptionYear
: 创始年份
url
: 项目地址,这里可以向项目的index连接
developers
: 项目开发者信息
contributors
: 项目贡献者信息
distributionManagement
: 项目的部署地址
issueManagement
: 项目缺陷跟踪信息
ciManagement
: 项目持续集成的部署信息
scm
: 项目的版本控制系统信息
mailingLists
: 项目的邮件地址列表信息
properties
: 自定义的maven属性
dependencies
: 项目依赖
dependencyMangement
: 项目依赖管理配置
repositories
: 项目仓库
build
: 项目源码目录配置、输出目录配置、插件配置、插件管理配置等
reporting
: 项目的输出目录配置、报告插件配置等
通过build参数可以看到插件配置也可以被继承
依赖管理
dependencies
与dependencyManagement
在父模块pom.xml
中的dependencies
中引入的依赖会被所有引用该父模块的子模块继承,但并不是所有的子模块都会用到父模块中声明的依赖,所以为了防止多余的依赖,父容器中可以通过dependencyManagement
来声明jar
包依赖。
dependencyManagement
中声明的依赖配置会被子模块继承,但是不会被实际使用,除非子模块显示通过groupId:artifactId
声明需要引用该依赖
使用dependencyManagement
的好处是可以在父模块中对jar
包版本进行统一管理,推荐这么做
import依赖范围
在前面依赖范围提到过import
,它的作用只会对pom.xml
中配置的dependencyManagement
有效
import
的作用是:将目标pom
中的dependencyManagement
配置导入并合并到当前pom.xml
中
import
依赖范围是除了使用代码复制和继承之外的又一个可以将外部配置导入的方式,下面是具体配置:
父项目b
<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.cbm.stu</groupId>
<artifactId>maven-parent-b</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<name>maven-parent-b</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
继承b
的子项目
<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.cbm.stu</groupId>
<artifactId>maven-study-mail</artifactId>
<version>2.1</version>
<packaging>jar</packaging>
<name>maven-study-mail</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<!-- 此处继承b 项目,type为pom,scope 为 import -->
<dependency>
<groupId>com.cbm.stu</groupId>
<artifactId>maven-parent-b</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 从继承的父项目中继承依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
import
依赖范围由于其特殊性,它的类型(type
)一般都是pom
,scope
为import
插件管理
与依赖管理相似的是插件管理,maven中提供了plugins
, pluginManagement
两个元素,这两个元素的用途与依赖管理中的dependencies
和dependencyManagement
用法一致
这里不做赘述
聚合与继承之间的关系
不同点:
- 聚合与继承是两个概念,其目的是完全不同的,聚合是为了解决多模块同时构建的问题,而继承则是为了解决多模块重复配置问题
- 对于聚合模块来说,它知道有哪些子模块需要被聚合,(<
modules
>),而对于继承来说它不知道有哪些子模块继承了它,但相反,子模块知道他们继承的是哪一个父模块(<parent
>)
聚合模块.png
继承模块.png
相同点:
聚合与继承模块pom
的类型(type
)都是pom
,他们都除了包含一个pom.xml
文件之外,没有其他东西
推荐做法:为了方便,可以将聚合和继承两者合成一个模块,在一个父模块中配置聚合和继承
约定优于配置
使用maven
比使用ant
配置更少,更方便,虽然用户感觉上自己配置的东西少了,其实是maven
内部将某一些配置提前预设好了,比如在超级pom
中可以看到的:
- 源码目录为
src/main/java
- 编译输出目录为
target/classes
- 打包方式为
jar
- 包输出目录为
target/
所有项目的pom.xml
都继承与超级pom
中的配置,超级pom
具体位置在:
${MVN_HOME}/lib/maven-model-builder-x.x.x.jar/org/apache/maven/model/pom-4.0.0.xml
反应堆
对于单模块,反应堆就是它本身,但对于多个模块项目来说,反应堆就包含了模块之间继承与依赖的关系
maven
的实际构建顺序是这样形成的:
-
maven
按序读取pom,如果该pom
没有依赖模块,则直接进行构建 - 如果依赖了其他模块,那么先构建其他模块
- 递归1,2直到完成整个项目的构建工作
特别说明,项目模块之间的依赖配置,不能出现循环依赖的现象,也就是A依赖B,B也依赖于A,这样的配置将会导致maven构建失败
裁剪反应堆
对聚合模块运行maven
命令比如mvn clean install
,maven
会根据计算出来的反应堆顺序将全部子模块都构建完毕并安装到本地仓库,为了选择性的构件某些模块进行构建而不是将所有模块进行构建,那么可以采用maven
提供的几条裁剪反应堆命令:
-am also make
构建模块同时构建所列模块依赖的其他模块
-amd also make dependency
构建模块同时构建依赖当前模块的其他模块
-pl --projects
构建指定的模块,多个模块用,分隔
-rf resume-from
在计算出的反应堆顺序基础上,从指定模块开始向后构建
下面是各个命令的实例:
假设存在account-parent
,account-email
,account-persist
三个模块,他们之间的关系如下:
-pl
:构建指定模块mvn clean install -pl account-parent
将会构建
account-parent
模块
-am
:构建模块并构建其依赖的其他模块
mvn clean install -pl account-email -am
将会构建account-parent/account-email模块
-amd
: 构建模块并构建依赖它的其他模块
mvn clean install -pl account-parent -amd
将会构建account-parent/account-email/account-persist
-rf
指定构建的起始模块,假设模块依赖关系如下
account-parent
- account-email
- account-persist
mvn clean install -pl account-parent -amd -rf account-persist
将会构建account-parent/account-persist
,而跳过account-email
模块的构建
好了,以上就是本章的重点知识,键盘敲到这里,再看看现在的时间0:39,再想到明天台风天还要上班,赶紧洗干净滚床上睡觉啦!!!