四. 生命周期
1. 概述
maven 的生命周期包含了一些有序的命名阶段, 有的阶段抽象了编译过程, 有的阶段抽象了打包过程. 当让 maven 构建一个项目的时候, 其实是让它一步步通过哪些预定义的有序的阶段, 并且运行所有注册到某个特定阶段的目标.
一个构建生命周期, 是一组精心组织的有序的阶段, 它的存在使得所有注册的目标有序运行.
2. 预设生命周期
2.1. clean
clean
是 maven 中最简单的生命周期, 包括了三个生命周期阶段
- pre-clean
- clean
- post-clean
其中第二步的 clean 阶段, 绑定了 clean 插件的 clean 目标 (clean:clean), 也是 clean 生命周期中最关键的一步操作.
但若单独执行 clean:clean
, 则不会完整执行 clean (生命周期) 中的三个阶段, 只会执行其中的 clean(阶段)
2.2. default
大部分 maven 用户会对默认生命周期比较熟悉, 它是一个软件应用程序构建过程的总体模型, 具体阶段如下
生命周期阶段 | 描述 |
---|---|
验证(validate) | 验证项目是正确的,所有必要的信息可用。 |
初始化(initialize) | 初始化构建状态,例如设置属性或创建目录。 |
产生来源(generate-sources) | 生成包含在编译中的任何源代码。 |
流程源(process-sources) | 处理源代码,例如过滤任何值。 |
生成资源(generate-resources) | 生成包含在包中的资源。 |
流程资源(process-resources) | 将资源复制并处理到目标目录中,准备打包。 |
编译(compile) | 编译项目的源代码。 |
工艺类(process-classes) | 从编译后处理生成的文件,例如对Java类进行字节码增强。 |
生成测试来源(generate-test-sources) | 生成包含在编译中的任何测试源代码。 |
流程测试来源(process-test-sources) | 处理测试源代码,例如过滤任何值。 |
生成测试资源(generate-test-resources) | 创建测试资源。 |
流程测试资源(process-test-resources) | 将资源复制并处理到测试目标目录中。 |
测试编译(test-compile) | 将测试源代码编译到测试目标目录中 |
流程检验类(process-test-classes) | 从测试编译中处理生成的文件,例如对Java类进行字节码增强。对于Maven 2.0.5及以上版本。 |
测试(test) | 使用合适的单元测试框架运行测试。这些测试不应该要求代码被打包或部署。 |
制备包(prepare-package) | 在实际包装之前,执行必要的准备包装的操作。这通常会导致打包的处理版本的包。(Maven 2.1及以上) |
打包(package) | 采取编译的代码,并以其可分发的格式(如JAR)进行打包。 |
预集成测试(pre-integration-test) | 在执行集成测试之前执行所需的操作。这可能涉及诸如设置所需环境等。 |
集成测试(integration-test) | 如果需要,可以将该包过程并部署到可以运行集成测试的环境中。 |
整合后的测试(post-integration-test) | 执行集成测试后执行所需的操作。这可能包括清理环境。 |
校验(verify) | 运行任何检查以验证包装是否有效并符合质量标准。 |
安装(install) | 将软件包安装到本地存储库中,以作为本地其他项目的依赖关系。 |
部署(deploy) | 在集成或发布环境中完成,将最终软件包复制到远程存储库,以与其他开发人员和项目共享。 |
通过使用默认生命周期中的阶段命令, 可以执行从开始到指定阶段的一系列阶段, 比如:
mvn compile, mvn test, mvn package, mvn install, mvn deploy
2.3. site
maven 不仅能从一个项目构建出软件构件, 它还能为一个或者一组项目生成项目文档和报告
项目文档和站点生成有一个专有的生命周期, 包括四个阶段
- pre-site
- site, 绑定了 site:site
- post-site
- site-deploy, 绑定了 site:deploy
打包类通常不会影响这个生命周期, 因为打包类型主要和构建的创建有关, 而和站点的生成没有太大关系
可以通过以下命令触发 site 生命周期
mvn site
3. 不同打包类型的生命周期
根据打包类型的不同, 绑定到生命周期的目标也不相同.
jar
项目会使用 jar: jar
来打包, 而 war
项目会使用 war: war
, pom
项目不需要编译, 使用 site: attach-descriptor
打包.
maven 还能使用其他的一些打包类型, 许多打包类型依赖于特定的插件来实现, 还可以使用自定义的打包类型并自定义生命周期.
在此不一一赘述.
五. 多模块项目
1. 项目间关系
项目之间有三种关系
-
依赖
A项目的正常构建需要B项目, 称为依赖:
使用
depenency
元素声明依赖 -
聚合
将多个项目聚集起来作为一个大项目, 项目之间可以没有直接关系
从上往下声明, 上级项目使用
modules
元素声明所包含的小项目 -
继承
定义一个父 pom, 子项目可以从这个 pom 中继承相应的配置内容, 可以简化子项目 pom 的配置
从下往上声明, 子项目使用
parent
元素声明父项目, 从什么地方继承配置
聚合与继承是两个不同的概念, 没有必然的联系, 但在实际的多模块项目中, 往往同时存在聚合与继承.
2. 聚合
聚合工程, 通常会包含多个待构建的项目, 打包类型往往是 pom, 而不是 jar
, war
之类具体的构件.
聚合工程的存在只是为了将很多项目归类在一起, 成为一个构建.
- 如图所示,
top-group
是一个聚合工程, 打包类型为pom
, 包含了sub-group
和project-c
两个工程, 而sub-group
又是一个聚合工程, 包含了project-a
和project-b
两个工程. - 当构建
top-group
的时候, maven 会检查其中的modules
元素, 如果有包含其他模块, 则会获取相应的 pom.xml, 以完成完整的构建工作.
聚合工程最大的意义在于简化多工程的构建工作, 当需要将相关的多个工程(不一定直接依赖), 一起构建时, 一种做法是按照一定的顺序完成每一个工程的构建, 如果构建的顺序不正确, 则会构建失败.
而聚合工程正是为了解决这种问题而存在, 使用聚合工程, 将多个项目作为这个聚合工程的模块, 然后执行整个聚合工程的构建. maven 会自动分析模块之间的关系, 确保按照正常的顺序完成构建.
当 maven 执行一个包含子模块的项目时, maven 首先会载入父 pom, 然后定位所有子模块 pom, 将所有的 pom 放入一个称为 maven 反应炉
的东西中, 分析模块之间的依赖关系, 根据依赖关系, 决定各个模块的编译顺序. 如果发现一个子模块需要依赖于其他子模块, 则会将该模块的构建顺序延后, 直到需要的模块都构建完成.
通常建议将需要先构建的子模块写在前面, 需要依赖其他子模块的写在后面.
要使用聚合工程, 需要将打包类型设为 pom
, 并使用 modules
指定要聚合的模块
<project>
<groupId>com.sonatype.maven</groupId>
<artifactId>top-group</artifactId>
<!-- 聚合工程通常都是 pom -->
<packaging>pom</packaging>
<version>1.0</version>
<!-- 将需要聚合的工程放在 modules 元素之下 -->
<modules>
<module>sub-group</module>
<module>project-c</module>
</modules>
...
</project>
3. 继承
有些情况下, 会想要一个项目从父 pom 中继承一些值, 比如在构建一个大型系统时, 不希望在每个小工程下重复地引入相同的依赖元素. 通过定义<parent>
元素使用继承, 就可以避免这种重复.
使用 parent
标签声明父级项目的坐标, 子模块的 pom 将会从父级 pom 继承一些内容, 如项目坐标, 依赖及插件的声明和引入等.
在父 pom 已经声明的信息, 在子 pom 中可以省略, 也可以声明新值以覆盖父 pom 中的值.
如果一个项目没有指定父 pom, 则会从超级 pom 中继承配置.
maven 假设父 pom 在本地仓库可用, 或者在当前项目的上级目录中 (…/pom.xml), 如果两个位置都不可用, 则需要使用 relativePath
元素告诉 maven 要从哪里获取
<parent>
<artifactId>mutilmvn</artifactId>
<groupId>com.loyofo</groupId>
<version