Maven 通过按生命周期顺序执行插件目标来构建项目。生命周期包含按顺序排列的阶段;调用某个阶段时,会执行该生命周期中该阶段及其之前的所有阶段。插件提供目标,而生命周期绑定则根据项目的打包类型选择要运行的目标。
项目模型与坐标 #
POM 使用 groupId、artifactId、version 和 packaging 标识构件。父 POM、依赖管理和导入的 BOM 可以集中管理版本,而不会将构件添加到类路径中。因此,dependencyManagement 只有在子项目声明依赖之后,才会约束这些依赖。
继承与聚合彼此独立。子项目继承 <parent> 指定的 POM;聚合器则在 <modules> 中列出 reactor 项目,并按依赖顺序构建它们。一个 POM 可以同时承担这两种角色,但模块不必继承自其聚合器。使用以下命令检查合并后的模型和活动配置文件:
mvn help:effective-pom
mvn help:active-profiles将仓库、凭据和部署配置分开管理:
- 仅当项目需要时,才提交项目仓库配置。
- 将凭据和组织专用镜像放入用户或 CI 的
settings.xml,而不是 POM。 - 显式声明依赖和插件版本,可以直接声明,也可以通过经过评审的管理部分声明。缺少插件版本会使构建依赖 Maven 的解析行为,而不是源代码树。
生命周期与阶段 #
Maven 提供 clean、default 和 site 生命周期。日常构建使用 default 生命周期:
| 阶段范围 | 用途 |
|---|---|
从 validate 到 process-resources | 验证模型、生成输入并准备资源。 |
从 compile 到 test | 编译生产代码和测试代码,然后执行单元测试。 |
package | 创建 JAR、WAR 或其他可分发构件。 |
从 pre-integration-test 到 post-integration-test | 准备、执行并拆除集成测试环境。 |
verify | 在测试之后执行质量检查。 |
install | 将构件添加到本地仓库。 |
deploy | 将构件发布到远程仓库。 |
mvn verify 会到达验证阶段但不会发布构件,因此适合作为 CI 基线。mvn clean verify 还会删除之前的构建输出。clean 生命周期包含 pre-clean、clean 和 post-clean;clean 会删除生成的构建文件。site 生命周期会生成项目文档,也可以发布这些文档。
插件、目标与执行 #
插件是构建时运行的代码,而不是项目依赖。在 build/plugins 中配置处于启用状态的构建插件。使用 build/pluginManagement 为子项目或同一个 POM 提供版本和共享配置,但它们仍必须显式启用这些配置。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>21</release>
</configuration>
</plugin>
</plugins>
</build>一次执行会将一个或多个目标绑定到某个阶段。特定打包类型的默认绑定会提供编译 Java 源代码、创建 JAR 等常见目标。如果执行中省略 <phase>,则使用 Mojo 的 defaultPhase;但它不会单独将任意第三方目标绑定到生命周期。
<plugin>
<groupId>org.example</groupId>
<artifactId>example-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals><goal>generate</goal></goals>
</execution>
</executions>
</plugin>可以使用前缀或完整坐标直接调用目标:
mvn dependency:tree
mvn org.apache.maven.plugins:maven-dependency-plugin:3.7.1:tree前缀解析可能会搜索已配置的插件组和仓库。当 POM 尚未声明该插件时,在自动化中优先使用完整坐标。
插件内部结构与前缀解析 #
插件构件由 <packaging>maven-plugin</packaging> 标识。其可执行单元是 Mojo,Mojo 作为 AbstractMojo 的子类实现。插件自身的 POM 可以通过 maven-plugin-plugin 定义 <goalPrefix>,该前缀会成为 CLI 中的短名称。
前缀解析分为以下几层:
- 如果项目已经声明了具有所请求前缀的插件,Maven 可以从有效 POM 中解析该插件;
- 否则,Maven 会检查内置的
org.apache.maven.plugins组,以及settings.xml中声明的其他pluginGroups; - 如有必要,Maven 会回退到
maven-XXX-plugin或XXX-maven-plugin等 artifactId 约定。
这套解析模型解释了为什么无需完整坐标即可运行 mvn dependency:tree,而自动化通常更倾向于使用明确的 groupId:artifactId:version:goal 形式。
@Mojo 上的 defaultPhase 属性只会为显式执行提供阶段。它不会为非官方插件创建自动绑定。生命周期绑定来自打包模型和 Maven 的内置默认绑定,而不是仅来自该注解。
依赖与作用域 #
Maven 根据作用域将直接依赖和传递依赖解析到类路径中:
| 作用域 | 主代码编译 | 主代码运行时 | 测试编译和运行时 |
|---|---|---|---|
compile | yes | yes | yes |
provided | yes | no | yes |
runtime | no | yes | yes |
test | no | no | yes |
仅当部署环境提供兼容的 API(例如 Servlet 容器)时,才使用 provided。runtime 适用于编译器不需要的驱动程序和实现。system 要求使用本地文件路径,并绕过正常的仓库解析,因此不应用于可复现构建。import 仅适用于 POM 依赖,并将 BOM 导入依赖管理。
使用 mvn dependency:tree 查找版本仲裁和排除项。Maven 的最近定义规则会在冲突的传递版本中进行选择;深度相同时,按声明顺序解析。直接声明或 dependencyManagement 条目可以使选择明确。排除项只适用于声明它的依赖路径,因此应优先使用管理部分或 BOM,而不是分散的排除项。
仓库、镜像与设置 #
仓库是构件来源。镜像是 settings.xml 中用于重定向对所选仓库请求的规则;它不会添加依赖,也不会替换仓库授权策略。
<mirrors>
<mirror>
<id>company-proxy</id>
<mirrorOf>central</mirrorOf>
<url>https://repository.example.invalid/maven-central</url>
</mirror>
</mirrors>全局设置文件位于 Maven 安装目录下,用户设置文件位于 ~/.m2/settings.xml。CI 应通过其密钥管理机制提供最小化的设置文件。不要将仓库密码存储在 POM 中。Maven 的 <relocation> 元数据允许发布者将过时坐标重定向到替代坐标。
Maven Wrapper #
提交 mvnw、mvnw.cmd 和 .mvn/wrapper/,使开发者和 CI 使用已声明的 Maven 发行版:
mvn wrapper:wrapper -Dmaven=3.9.9
./mvnw clean verify更新 Wrapper 时,检查发行版 URL 和校验和。Wrapper 固定的是 Maven 本身;插件和依赖版本仍需要通过 POM 管理。
评论
在 GitHub 上阅读或评论(发表评论需要登录)