第一章:Maven 概述与环境搭建
1.1 什么是 Maven
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Maven | Maven 是一个基于项目对象模型(POM)的自动化构建工具,主要用于 Java 项目的构建、依赖管理和项目信息管理。它通过标准化的构建流程和约定优于配置的原则,简化项目构建过程。 | Maven 不仅是构建工具,更是项目管理工具,可生成项目报告、站点文档等。 |
| POM (Project Object Model) | 项目对象模型,是 Maven 的核心。每个 Maven 项目都包含一个 pom.xml 文件,定义了项目的配置信息,如坐标、依赖、插件、构建配置等。 | pom.xml 是 Maven 项目的配置中心,必须正确编写以确保项目正常构建。 |
| 构建(Build) | 将源代码转换为可执行程序或可部署构件的过程,包括编译、测试、打包、部署等步骤。Maven 提供标准化的生命周期来管理构建过程。 | 构建过程可重复、自动化,避免手动操作带来的错误。 |
| 约定优于配置(Convention over Configuration) | Maven 提供默认的项目结构和行为,开发者无需手动配置即可快速开始。只有在需要偏离默认约定时才需额外配置。 | 减少配置复杂度,提升开发效率,但需熟悉默认约定(如 src/main/java 存放源码)。 |
1.2 Maven 的核心特性与优势
| 特性名称 | 说明 | 注意事项 |
|---|---|---|
| 标准化构建流程 | Maven 定义了清晰的构建生命周期(如 compile、test、package、install、deploy),所有项目遵循统一流程。 | 开发者无需从零设计构建脚本,提升团队协作效率。 |
| 依赖管理 | 自动下载和管理项目所需的第三方库(JAR 包),解决手动下载、版本混乱、依赖冲突等问题。 | 需合理使用依赖范围(如 test、provided)避免运行时错误。 |
| 项目信息管理 | 通过 pom.xml 统一管理项目名称、版本、开发者、许可证等元数据。 | 有助于生成项目文档、报告,提升项目可维护性。 |
| 插件机制 | 构建任务由插件完成,Maven 提供大量官方插件(如 compiler、surefire),支持自定义插件。 | 插件可扩展性强,但需注意版本兼容性。 |
| 多模块项目支持 | 支持将大型项目拆分为多个子模块,统一构建和管理。 | 适用于复杂系统,需合理设计模块划分和依赖关系。 |
| 仓库机制 | 本地、远程、中央仓库协同工作,实现依赖的存储、共享和分发。 | 私服(如 Nexus)可用于企业内部依赖管理,提升安全性和构建速度。 |
| 可重复构建 | 相同输入(pom.xml 和源码)始终产生相同输出,确保构建一致性。 | 有利于持续集成(CI)和生产部署。 |
1.3 Maven 与构建工具对比(Ant、Gradle)
| 对比维度 | Maven | Ant | Gradle | 注意事项 |
|---|---|---|---|---|
| 构建方式 | 基于约定和生命周期,声明式配置 | 基于目标(target)的命令式脚本 | 基于 Groovy/Kotlin DSL 的声明式 + 脚本式 | Maven 更规范,Ant 更灵活,Gradle 兼具灵活性与性能。 |
| 配置文件 | pom.xml(XML 格式) | build.xml(XML 格式) | build.gradle(Groovy/Kotlin) | Gradle 配置更简洁,Maven 和 Ant 的 XML 易冗长。 |
| 依赖管理 | 内置强大依赖管理,支持自动下载和传递 | 无内置依赖管理,需手动管理 JAR 包 | 内置依赖管理,支持 Maven/Gradle 仓库 | Ant 依赖管理繁琐,Maven 和 Gradle 更适合现代项目。 |
| 执行效率 | 一般 | 一般 | 高(增量构建、缓存、并行执行) | Gradle 构建速度显著优于 Maven 和 Ant,尤其在大型项目中。 |
| 学习曲线 | 中等,需理解 POM 和生命周期 | 简单(基础脚本),复杂时陡峭 | 中等偏高(需学习 DSL) | Maven 概念较多,但结构清晰;Gradle 功能强大但语法需学习。 |
| 社区与生态 | 非常成熟,广泛用于企业项目 | 老牌工具,新项目较少使用 | 快速增长,Android 官方推荐 | Maven 生态最丰富,Gradle 在新项目中越来越流行。 |
| 多语言支持 | 主要支持 Java | 支持多种语言(通过任务扩展) | 支持 Java、Kotlin、Scala、Android 等 | Ant 和 Gradle 更适合多语言项目。 |
| 生命周期 | 预定义完整生命周期(default、clean、site) | 无预定义生命周期,完全自定义 | 支持标准生命周期,可自定义 | Maven 生命周期标准化程度高,利于团队统一。 |
1.4 Maven 环境安装与配置
| 步骤 | 操作说明 | 注意事项 |
|---|---|---|
| 安装 JDK | Maven 依赖 Java 环境,需先安装 JDK 8 或更高版本。 | 确保 JAVA_HOME 环境变量正确指向 JDK 安装目录,而非 JRE。 |
| 下载 Maven | 从官网 https://maven.apache.org 下载二进制压缩包(apache-maven-x.x.x-bin.zip)。 | 建议选择最新稳定版本,避免使用过旧版本。 |
| 解压 Maven 包 | 将下载的压缩包解压到指定目录(如 C:\maven 或 /opt/maven)。 | 解压路径避免包含空格或中文字符,防止后续构建出错。 |
| 配置环境变量 | 设置 MAVEN_HOME 或 M2_HOME 指向 Maven 解压目录,并将 %MAVEN_HOME%\bin(Windows)或 $MAVEN_HOME/bin(Linux/macOS)添加到 PATH。 | 确保命令行可全局执行 mvn 命令。 |
| 验证安装 | 打开终端,执行 mvn -v 或 mvn --version。 | 正确输出 Maven 版本、Java 版本、Maven 主目录等信息表示安装成功。 |
配置 settings.xml | 可选:修改 %MAVEN_HOME%\conf\settings.xml 文件,配置本地仓库路径、镜像、代理等。 | 企业环境中常配置私服镜像以提升依赖下载速度。 |
1.5 验证安装与基础命令测试
| 命令名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 显示 Maven 版本信息 | mvn -v 或 mvn --version | 验证 Maven 是否安装成功,查看 Maven、JDK 和操作系统版本等环境信息。 | mvn -v | 必须正确显示 Maven 版本、Java 版本和 MAVEN_HOME 路径,否则安装或配置有误。 |
| 创建简单 Maven 项目 | mvn archetype:generate | 使用 archetype 插件生成标准 Maven 项目骨架。 | mvn archetype:generate | 执行后需交互式选择模板(如 maven-archetype-quickstart)并填写 groupId、artifactId 等。 |
| 强制跳过交互式输入创建项目 | mvn archetype:generate -DgroupId=com.example -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false | 非交互式快速生成最简单的 Maven Java 项目。 | 如上所示 | -D 参数用于指定项目坐标和模板;-DinteractiveMode=false 禁用交互模式。 |
| 编译主源代码 | mvn compile | 将 src/main/java 下的 Java 源文件编译为 class 文件,输出到 target/classes。 | mvn compile | 若依赖缺失会自动下载;编译失败时检查源码语法和依赖配置。 |
| 编译并运行单元测试 | mvn test | 编译 src/test/java 下的测试代码,并执行所有单元测试。 | mvn test | 测试结果输出在控制台,失败的测试会标记;确保测试类遵循命名规范(如 *Test)。 |
| 打包项目 | mvn package | 对项目进行编译、测试后,根据 pom.xml 中的 packaging 类型(如 jar、war)打包。 | mvn package | 打包文件生成在 target/ 目录下;若测试失败默认中断打包。 |
| 将构件安装到本地仓库 | mvn install | 将当前项目打包后的构件(如 JAR)安装到本地仓库(~/.m2/repository),供其他项目依赖。 | mvn install | 是模块化开发中常用命令,使当前项目可作为依赖被其他本地项目使用。 |
| 清理构建目录 | mvn clean | 删除 target/ 目录及其内容,清除上次构建产生的文件。 | mvn clean | 建议在重新构建前执行,确保构建干净;不会影响源码和配置文件。 |
| 打印项目依赖树 | mvn dependency:tree | 显示项目直接和传递依赖的层级结构,用于分析依赖冲突和冗余。 | mvn dependency:tree | 输出信息量大,可结合 grep 过滤;是排查依赖问题的核心命令。 |
| 下载源码和文档 | mvn dependency:sources / mvn dependency:resolve -Dclassifier=javadoc | 分别尝试下载依赖项的源码和 JavaDoc 文档,便于 IDE 调试和查看。 | mvn dependency:sources | 并非所有依赖都提供源码或文档,部分可能下载失败。 |
第二章:Maven 核心概念
2.1 项目对象模型(POM)
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| POM (Project Object Model) | 项目对象模型,是 Maven 的核心概念。每个 Maven 项目都必须包含一个 pom.xml 文件,它以 XML 格式定义了项目的配置信息,包括项目坐标、依赖、构建配置、插件、属性等。 | pom.xml 是 Maven 项目的基础,Maven 通过读取该文件来执行构建任务。 |
| 父 POM (Super POM) | Maven 内置的默认 POM,所有项目 POM 都隐式继承它。它定义了默认的仓库、插件版本、目录结构等。可通过 mvn help:effective-pom 查看实际生效的 POM。 | 理解 Super POM 有助于明白为何某些配置(如源码目录)无需显式声明。 |
| 最小化 POM | 一个合法的 pom.xml 至少需要包含 modelVersion、groupId、artifactId 和 version 四个元素。 | modelVersion 通常为 4.0.0,表示 POM 模型版本。 |
| 继承 (Inheritance) | 子项目可以继承父项目的 POM 配置(通过 <parent> 元素),实现配置复用,常用于多模块项目。 | 父 POM 通常打包为 pom 类型,不包含实际代码。 |
| 聚合 (Aggregation) | 又称多模块项目,一个父项目可以聚合多个子模块,通过 <modules> 元素列出子模块目录,实现统一构建。 | 聚合 POM 的 packaging 必须为 pom。 |
| 可变性 (Reactor) | 在多模块构建中,Maven 的 Reactor 机制会分析模块间的依赖关系,自动确定构建顺序。 | 构建顺序不一定按 pom.xml 中模块声明的顺序,而是按依赖拓扑排序。 |
2.2 坐标(GroupId、ArtifactId、Version)
| 坐标元素 | 说明 | 注意事项 |
|---|---|---|
groupId | 定义当前 Maven 项目所属的组织或团体,通常与域名反向对应(如 com.example)。用于区分不同组织的项目。 | 建议使用公司或组织域名反写,确保全局唯一性。 |
artifactId | 定义当前项目在 groupId 下的唯一标识,通常是项目名称(如 my-web-app)。与 groupId 共同确定项目位置。 | 应简洁明了,避免使用特殊字符。 |
version | 定义当前项目的版本号,如 1.0.0、2.1.3-SNAPSHOT 等。SNAPSHOT 表示开发中的快照版本。 | 发布版本(无 SNAPSHOT)是稳定的;快照版本每次构建都会检查更新。 |
packaging | 定义项目的打包类型,常见值有 jar、war、pom、ear 等。默认为 jar。影响构建生命周期和输出文件。 | 不同 packaging 触发不同的默认插件绑定(如 war 会绑定 maven-war-plugin)。 |
classifier | 可选元素,用于区分同一 artifactId 和 version 的不同构建产物(如 sources、javadoc)。 | 不能直接定义在 pom.xml 中,由插件生成(如 mvn source:jar 生成 *-sources.jar)。 |
示例坐标定义:
groupId: com.example
artifactId: my-app
version: 1.0.0-SNAPSHOT
packaging: jar
该坐标唯一确定一个构件,在仓库中的路径为:com/example/my-app/1.0.0-SNAPSHOT/my-app-1.0.0-SNAPSHOT.jar
2.3 仓库(本地、远程、中央仓库)
| 仓库类型 | 说明 | 注意事项 |
|---|---|---|
| 本地仓库 (Local Repository) | 位于用户本地磁盘(默认 ~/.m2/repository),存储从远程仓库下载的依赖和本地安装的构件。Maven 优先从本地查找依赖。 | 可通过 settings.xml 修改路径;删除后可重新下载,但会增加构建时间。 |
| 中央仓库 (Central Repository) | Maven 官方维护的公共仓库(https://repo.maven.apache.org/maven2),包含大量开源 Java 库。所有 Maven 项目默认可访问。 | 不包含所有开源库(如某些商业库或较新版本),需额外配置其他远程仓库。 |
| 远程仓库 (Remote Repository) | 项目自定义的第三方仓库,可以是公共仓库(如 JCenter 已停用)或企业私有仓库(如 Nexus、Artifactory)。 | 需在 pom.xml 或 settings.xml 中配置,用于获取中央仓库没有的依赖。 |
| 私服 (Private Repository) | 企业内部搭建的远程仓库,用于统一管理内部构件、缓存外部依赖、提升安全性与构建速度。 | 可代理中央仓库,减少外网访问;支持权限控制和审计。 |
| 镜像仓库 (Mirror) | 为远程仓库设置的代理,所有对原仓库的请求将被重定向到镜像。常用于加速下载(如国内使用阿里云镜像)。 | 在 settings.xml 中配置,使用 <mirrorOf> 指定被代理的仓库(如 central)。 |
仓库查找顺序: 本地仓库 → 镜像仓库(若配置)→ 远程仓库 → 中央仓库
2.4 依赖管理机制
| 机制名称 | 说明 | 注意事项 |
|---|---|---|
| 直接依赖 (Direct Dependency) | 项目在 pom.xml 的 <dependencies> 中直接声明的依赖。 | 明确列出项目所需库,版本由 dependency 或 dependencyManagement 控制。 |
| 传递性依赖 (Transitive Dependency) | Maven 自动解析并引入直接依赖所依赖的库。例如 A 依赖 B,B 依赖 C,则 C 是 A 的传递性依赖。 | 可能导致依赖冲突或引入不必要的库,需用依赖树分析。 |
| 依赖范围 (Scope) | 控制依赖在不同构建阶段的可见性和使用范围,如 compile、test、provided 等。 | 正确使用 scope 可避免运行时类冲突(如 provided 不打包到最终构件)。 |
| 依赖调解 (Dependency Mediation) | 当存在多个版本的同一依赖时,Maven 采用”路径最近优先”原则选择版本。若路径相同,则”先声明优先”。 | 可通过在 pom.xml 中直接声明依赖来强制指定版本。 |
| 依赖排除 (Exclusion) | 使用 <exclusions> 排除某个依赖的特定传递性依赖,防止其被引入。 | 常用于排除冲突或过时的传递依赖。 |
| 可选依赖 (Optional) | 使用 <optional>true</optional> 标记依赖为可选,表示该依赖不会被传递。 | 适用于功能扩展库,使用者需显式声明才能使用。 |
| 依赖管理 (Dependency Management) | 在父 POM 的 <dependencyManagement> 中统一声明依赖版本,子模块继承但不自动引入。 | 实现版本集中管理,避免版本混乱,是多模块项目的最佳实践。 |
2.5 构建生命周期(Build Lifecycle)
| 生命周期名称 | 包含阶段(部分) | 用途 | 注意事项 |
|---|---|---|---|
default | validate → compile → test → package → verify → install → deploy | 处理项目部署的核心生命周期,从源码到发布。 | 最常用,mvn compile、mvn package 等命令即执行该周期的特定阶段。 |
clean | pre-clean → clean → post-clean | 清理项目,删除 target/ 等构建输出目录。 | mvn clean 执行该周期,确保干净构建。 |
site | pre-site → site → post-site → site-deploy | 生成项目站点文档,包含项目信息、报告、依赖列表等。 | mvn site 生成文档,mvn site-deploy 发布文档。 |
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 阶段 (Phase) | 生命周期中的一个步骤,每个阶段代表构建过程的一个特定任务(如 compile 编译源码)。 | 阶段按顺序执行,调用某一阶段时,会自动执行之前的所有阶段。 |
| 绑定 (Binding) | 插件目标(Goal)与生命周期阶段的关联。例如 compiler:compile 默认绑定到 compile 阶段。 | 可自定义绑定,改变默认行为。 |
| 跳过阶段 | 可通过参数跳过某些阶段,如 -Dmaven.test.skip=true 跳过测试和编译测试代码。 | 谨慎使用,确保跳过不会影响构建完整性。 |
2.6 插件(Plugins)与目标(Goals)
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 插件 (Plugin) | Maven 的功能单元,用于执行具体的构建任务(如编译、打包、测试)。插件由 groupId、artifactId 和 version 唯一标识。 | 大部分插件由 org.apache.maven.plugins 提供,可自定义开发。 |
| 目标 (Goal) | 插件中的一个具体任务。一个插件可包含多个目标(如 compiler 插件有 compile 和 testCompile)。 | 目标是实际执行的最小单元。 |
| 命令格式 | mvn [plugin-prefix]:[goal] | plugin-prefix 是插件的简称(如 compiler),可在中央仓库查询。 |
| 默认绑定 | Maven 根据项目的 packaging 类型自动绑定插件目标到生命周期阶段。 | 如 jar 项目自动绑定 maven-compiler-plugin:compile 到 compile 阶段。 |
| 显式配置插件 | 在 pom.xml 的 <build><plugins> 中配置插件版本、参数等。 | 建议显式声明插件版本,避免使用默认版本带来的不确定性。 |
| 插件前缀 | 插件的简称,用于命令行调用(如 tomcat7:run)。映射关系存储在插件元数据中。 | 并非所有插件都有前缀,可通过 mvn help:describe -Dplugin=groupId:artifactId 查看。 |
示例:常用插件目标
| 插件前缀 | 目标名称 | 用途 | 命令示例 |
|---|---|---|---|
compiler | compile | 编译主源码 | mvn compiler:compile |
surefire | test | 执行单元测试 | mvn surefire:test |
jar | jar | 打包为 JAR 文件 | mvn jar:jar |
exec | java | 运行 Java 类 | mvn exec:java -Dexec.mainClass="com.example.Main" |
dependency | tree | 显示依赖树 | mvn dependency:tree |
第三章:Maven 项目结构与创建
3.1 标准项目目录结构
| 目录/文件路径 | 说明 | 注意事项 |
|---|---|---|
src/main/java | 存放项目的主 Java 源代码文件(.java)。 | 包结构需与 pom.xml 中的 groupId 和 artifactId 对应。 |
src/main/resources | 存放主代码所需的资源文件,如配置文件(.properties、.xml)、静态资源等。 | 编译后这些文件会被复制到输出目录的 classpath 下。 |
src/test/java | 存放单元测试的 Java 源代码文件(如 JUnit 测试类)。 | 测试代码不会被打包到最终构件中。 |
src/test/resources | 存放测试代码所需的资源文件,如测试专用配置。 | 仅在测试阶段可用,不包含在发布包中。 |
src/main/webapp | (仅 Web 项目)存放 Web 应用资源,如 JSP、HTML、WEB-INF 等。 | 当 packaging 为 war 时需要此目录。 |
target/ | Maven 构建过程的输出目录,编译后的 class 文件、打包的 JAR/WAR 等均在此。 | 可安全删除,执行构建命令后会重新生成;不应提交到版本控制系统。 |
pom.xml | 项目核心配置文件,定义项目坐标、依赖、插件、构建配置等。 | 必须位于项目根目录;是 Maven 识别项目的标志。 |
src/main/filters | 存放属性过滤文件(.properties),用于资源文件中的占位符替换。 | 需在 pom.xml 中启用资源过滤功能。 |
src/assembly | 存放程序集描述文件,用于自定义打包内容(配合 maven-assembly-plugin)。 | 非必需,用于复杂打包需求。 |
src/site | 存放项目站点文档的源文件。 | 用于生成项目文档网站。 |
示例结构:
my-app/
├── pom.xml
└── src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── App.java
│ └── resources/
│ └── application.properties
└── test/
├── java/
│ └── com/
│ └── example/
│ └── AppTest.java
└── resources/
└── test-config.properties
3.2 手动创建 Maven 项目
| 步骤 | 操作说明 | 注意事项 |
|---|---|---|
| 创建项目根目录 | 在文件系统中创建项目主目录(如 my-app)。 | 目录名通常与 artifactId 一致。 |
| 创建标准源码目录 | 在项目根目录下创建 src/main/java 和 src/test/java 目录。 | 必须严格遵循 Maven 默认目录结构,否则无法正确编译。 |
| 编写主程序类 | 在 src/main/java 下按包路径创建 Java 类文件(如 com/example/App.java)。 | 类中应包含主方法(public static void main)以便运行。 |
| 编写测试类 | 在 src/test/java 下创建对应的测试类(如 com/example/AppTest.java)。 | 建议使用 JUnit 框架,测试类名通常以 Test 结尾。 |
创建 pom.xml | 在项目根目录创建 pom.xml 文件,至少包含 modelVersion、groupId、artifactId、version。 | packaging 默认为 jar,若为 Web 项目需设为 war。 |
| 添加必要依赖 | 在 <dependencies> 中添加 junit-jupiter-api 等测试依赖。 | 测试依赖 scope 应设为 test。 |
| 验证项目结构 | 执行 mvn compile 编译主代码,mvn test 运行测试。 | 若无错误表示项目结构和配置正确。 |
最小化 pom.xml 示例:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3.3 使用 archetype 插件生成项目
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 交互式生成项目 | mvn archetype:generate | 启动向导模式,通过交互选择模板并输入项目信息生成项目骨架。 | mvn archetype:generate | 首次使用需下载 archetype 目录,可能较慢;适合学习和尝试不同模板。 |
| 非交互式生成简单 Java 项目 | mvn archetype:generate -DgroupId=... -DartifactId=... -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false | 快速生成包含基本结构和示例代码的 Java 项目,无需交互。 | mvn archetype:generate -DgroupId=com.example -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false | 最常用方式,适合脚本化创建项目。 |
| 生成 Web 项目 | mvn archetype:generate -DgroupId=... -DartifactId=... -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false | 生成标准的 Maven Web 项目结构,包含 webapp 目录和基础 web.xml。 | mvn archetype:generate -DgroupId=com.example -DartifactId=my-web -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false | 生成的 web.xml 版本较旧,可根据需要升级。 |
| 指定 archetype 版本 | ... -DarchetypeVersion=1.4 | 明确指定使用的 archetype 模板版本,避免使用默认或过时版本。 | ... -DarchetypeVersion=1.4 | 建议显式指定版本以保证一致性。 |
| 指定远程仓库 URL | ... -DarchetypeCatalog=internal -DremoteRepositories=https://... | 当使用私有仓库中的 archetype 时,指定其 URL。 | ... -DarchetypeCatalog=remote -DremoteRepositories=https://nexus.example.com/repository/maven-public | 企业环境中常用于内部项目模板。 |
| 列出可用 archetype | mvn archetype:generate -Dfilter=maven-archetype- | 在交互模式下,通过 filter 快速筛选 archetype 列表。 | mvn archetype:generate -Dfilter=maven-archetype- | 方便查找官方 archetype。 |
3.4 多模块项目结构简介
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 聚合 POM (Aggregator) | 父项目 pom.xml 中通过 <modules> 元素列出所有子模块,实现统一构建。父项目 packaging 必须为 pom。 | 执行 mvn install 会在父目录构建所有模块。 |
| 继承 POM (Parent) | 子模块通过 <parent> 元素继承父 POM 的配置(如依赖管理、插件、属性)。 | 父 POM 可集中管理版本,减少重复配置。 |
| 模块目录 | 每个子模块是一个独立的 Maven 项目,拥有自己的 pom.xml 和标准目录结构。 | 模块目录名通常与 artifactId 一致。 |
| 构建顺序 | Maven Reactor 机制自动分析模块间依赖,确定构建顺序。 | 若模块 A 依赖模块 B,则 B 必须先于 A 构建。 |
| 相对路径 | <relativePath> 元素指定父 POM 的位置,默认为 ../pom.xml。 | 若父 POM 在上级目录可省略;否则需明确指定。 |
示例多模块结构:
my-parent/
├── pom.xml (packaging: pom, 包含 <modules>)
├── module-a/
│ └── pom.xml (<parent> 指向 my-parent)
├── module-b/
│ └── pom.xml (<parent> 指向 my-parent,可能依赖 module-a)
└── module-web/
└── pom.xml (<parent> 指向 my-parent,依赖 module-a 和 module-b)
父 POM 片段示例:
<packaging>pom</packaging>
<modules>
<module>module-a</module>
<module>module-b</module>
<module>module-web</module>
</modules>
第四章:POM 文件详解
4.1 pom.xml 基本结构
| 元素名称 | 说明 | 注意事项 |
|---|---|---|
<project> | 根元素,所有其他元素都包含在其中。 | 必须存在,且是 XML 文档的顶层标签。 |
xmlns | 定义 POM 的命名空间,固定为 http://maven.apache.org/POM/4.0.0。 | 声明使用的 POM 模型版本。 |
xsi:schemaLocation | 指定 XML Schema 位置,用于 IDE 验证和自动补全。 | 开发时有助于减少配置错误。 |
<modelVersion> | 指定 POM 模型版本,当前必须为 4.0.0。 | 固定值,表示使用 Maven 2/3 的 POM 格式。 |
<groupId> | 项目所属组织标识。 | 通常与公司域名反向对应(如 com.example)。 |
<artifactId> | 项目在组织内的唯一标识。 | 通常是项目名称,简洁明确。 |
<version> | 项目版本号。 | 可使用 SNAPSHOT 表示开发中版本。 |
<packaging> | 打包类型,默认为 jar。 | 常见值:jar、war、pom、ear。 |
<name> | 项目的描述性名称,用于生成文档或展示。 | 非必需,但建议填写以增强可读性。 |
<description> | 项目详细描述。 | 非必需,可用于生成项目站点。 |
<url> | 项目主页 URL。 | 非必需,企业项目可指向内部文档系统。 |
最小化完整结构示例:
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
</project>
4.2 基础配置元素(modelVersion、packaging 等)
| 元素名称 | 说明 | 注意事项 |
|---|---|---|
<modelVersion> | POM 模型版本,当前唯一有效值为 4.0.0。 | 必需,Maven 通过此值解析 POM 文件结构。 |
<groupId> | 项目所属组织的唯一标识符。 | 建议使用反向域名确保全局唯一性。 |
<artifactId> | 项目自身的唯一标识符。 | 通常小写,使用连字符分隔单词(如 my-web-app)。 |
<version> | 项目版本号,格式通常为 主版本.次版本.修订号[-限定符]。 | -SNAPSHOT 表示快照版本,每次构建都会更新;发布版本应去掉 SNAPSHOT。 |
<packaging> | 项目打包类型,影响构建生命周期和默认插件绑定。 | 默认为 jar;Web 项目用 war;聚合/父项目用 pom。 |
<name> | 项目的可读名称,用于展示。 | 非必需,但有助于团队协作和文档生成。 |
<description> | 项目功能的简要描述。 | 非必需,建议填写。 |
<url> | 项目主页或文档地址。 | 非必需,可用于链接到 Confluence 或 GitHub 页面。 |
<inceptionYear> | 项目起始年份。 | 非必需,用于版权信息等。 |
<organization> | 组织信息,包含 <name> 和 <url>。 | 非必需,多用于开源项目。 |
<licenses> | 项目使用的许可证信息(如 Apache License 2.0)。 | 开源项目必需,企业项目可选。 |
<developers> | 开发者列表,包含姓名、邮箱、角色等。 | 非必需,用于项目管理和贡献记录。 |
4.3 依赖声明(dependencies)
| 元素名称 | 说明 | 注意事项 |
|---|---|---|
<dependencies> | 包含一个或多个 <dependency> 元素,声明项目直接依赖。 | 是依赖管理的核心部分。 |
<dependency> | 声明一个具体的依赖项。 | 必须包含 groupId、artifactId、version。 |
<groupId> | 被依赖库的组织 ID。 | 必需,与中央仓库坐标一致。 |
<artifactId> | 被依赖库的项目 ID。 | 必需。 |
<version> | 被依赖库的版本号。 | 必需,除非由 dependencyManagement 控制。 |
<type> | 依赖类型,默认为 jar。其他如 pom、war、ejb 等。 | 通常省略,Maven 自动推断。 |
<scope> | 依赖的作用范围(如 compile、test)。 | 见 4.4 节详解。 |
<optional> | 是否为可选依赖(true/false)。 | 见 4.7 节详解。 |
<exclusions> | 排除该依赖的传递性依赖。 | 见 4.6 节详解。 |
依赖声明示例:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.21</version>
</dependency>
</dependencies>
4.4 依赖范围(scope)
| 范围名称 | 编译期可见 | 测试期可见 | 运行期可见 | 传递性 | 用途说明 | 注意事项 |
|---|---|---|---|---|---|---|
compile | 是 | 是 | 是 | 是 | 默认范围,适用于所有阶段,依赖会打包到最终构件中。 | 用于核心业务逻辑依赖(如 Spring、Hibernate)。 |
test | 否 | 是 | 否 | 否 | 仅在测试编译和执行阶段可用,不会被打包或部署。 | 用于单元测试框架(如 JUnit、TestNG)。 |
provided | 是 | 是 | 否 | 是 | 编译和测试需要,但期望 JDK 或运行容器(如 Tomcat)提供,不打包。 | Web 应用中用于 Servlet API、JSP API 等。 |
runtime | 否 | 是 | 是 | 是 | 编译不需要,但测试和运行需要。 | 用于 JDBC 驱动、日志实现等接口与实现分离的场景。 |
system | 是 | 是 | 是 | 是 | 类似 provided,但必须通过 systemPath 指定本地 JAR 路径。 | 不推荐使用,破坏了可移植性;应优先安装到本地仓库。 |
import | - | - | - | - | 仅用于 <dependencyManagement> 中,导入其他 POM 的依赖管理配置。 | packaging 必须为 pom;常用于引入 Spring Boot BOM。 |
4.5 依赖传递与冲突解决
| 机制名称 | 说明 | 注意事项 |
|---|---|---|
| 传递性依赖 | A 依赖 B,B 依赖 C,则 A 会自动依赖 C,无需在 A 的 pom.xml 中声明。 | 可能引入大量间接依赖,使用 mvn dependency:tree 查看完整依赖树。 |
| 路径最近优先 | 当存在多个版本的同一依赖时,Maven 选择依赖路径最短的版本。 | 例如 A→B→C(1.0) 和 A→D→E→C(2.0),则选择 C(1.0),因为路径更短。 |
| 先声明优先 | 若路径长度相同,则先在 pom.xml 中声明的依赖其传递依赖优先被选用。 | 依赖声明顺序可能影响最终版本选择,建议显式声明关键依赖版本。 |
| 版本锁定 | 在 <dependencyManagement> 中统一声明版本,确保一致性。 | 多模块项目最佳实践,避免版本碎片化。 |
| 依赖树分析 | 使用 mvn dependency:tree 命令查看所有直接和传递依赖及其版本。 | 是排查冲突的核心手段,可结合 -Dverbose 显示被忽略的依赖。 |
| 冲突表现 | 类找不到(ClassNotFoundException)、方法不存在(NoSuchMethodError)等。 | 通常由不同版本的同一库引起,需通过依赖树定位并排除或升级。 |
4.6 依赖排除(exclusions)
| 元素名称 | 说明 | 注意事项 |
|---|---|---|
<exclusions> | 包含一个或多个 <exclusion> 元素,用于排除传递性依赖。 | 放在 <dependency> 内部。 |
<exclusion> | 定义一个要排除的依赖项。 | 必须指定 groupId 和 artifactId。 |
<groupId> | 要排除的依赖的组织 ID。 | 必需。 |
<artifactId> | 要排除的依赖的项目 ID。 | 必需。 |
排除示例(排除 log4j):
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.21</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
4.7 可选依赖(optional)
| 元素名称 | 说明 | 注意事项 |
|---|---|---|
<optional> | 布尔值(true/false),标记依赖是否为可选。 | 默认为 false。 |
可选依赖示例:
<dependency>
<groupId>com.example</groupId>
<artifactId>email-support</artifactId>
<version>1.0.0</version>
<optional>true</optional>
</dependency>
说明: 当其他项目依赖本项目时,不会自动继承
email-support这个依赖,使用者必须显式声明才能使用邮件功能。
4.8 属性(properties)配置
| 属性类型 | 语法示例 | 用途说明 | 注意事项 |
|---|---|---|---|
| 内建属性 | ${basedir} | 指向项目根目录。 | 常用于文件路径引用。 |
| POM 属性 | ${project.version} | 引用当前 POM 的元素值,如 version、groupId 等。 | 可简化配置,避免重复。 |
| 自定义属性 | <my.version>1.2.3</my.version> → ${my.version} | 用户在 <properties> 中定义的属性。 | 常用于统一管理版本号。 |
| Settings 属性 | ${settings.localRepository} | 引用 settings.xml 中的值。 | 如本地仓库路径。 |
| Java 系统属性 | ${java.home} | JVM 系统属性,可通过 System.getProperties() 获取。 | 如 os.name、user.home 等。 |
| 环境变量属性 | ${env.JAVA_HOME} | 操作系统环境变量。 | 注意跨平台兼容性。 |
属性配置示例:
<properties>
<java.version>8</java.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring.version>5.3.21</spring.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
4.9 构建配置(build)
| 元素名称 | 说明 | 注意事项 |
|---|---|---|
<build> | 构建配置的根元素,包含最终名称、目录、资源、插件等。 | 非必需,但通常用于自定义构建行为。 |
<finalName> | 指定打包后的文件名(不含扩展名)。 | - |
<directory> | 指定构建输出目录,默认为 target。 | 可修改,但不推荐。 |
<sourceDirectory> | 主源码目录,默认为 src/main/java。 | 可覆盖默认约定。 |
<testSourceDirectory> | 测试源码目录,默认为 src/test/java。 | - |
<resources> | 配置主资源文件目录及其过滤行为。 | 见 4.11 节详解。 |
<testResources> | 配置测试资源文件目录。 | 默认为 src/test/resources。 |
<plugins> | 声明构建过程中使用的插件及其配置。 | 见 4.10 节详解。 |
<pluginManagement> | 定义插件的默认配置,供子模块继承,避免重复配置。 | 多模块项目中用于集中管理插件版本和配置。 |
4.10 插件配置(plugins)
| 元素名称 | 说明 | 注意事项 |
|---|---|---|
<plugins> | 包含一个或多个 <plugin> 元素。 | 放在 <build> 下。 |
<plugin> | 声明一个插件。 | 必须包含 groupId、artifactId、version。 |
<groupId> | 插件的组织 ID,通常为 org.apache.maven.plugins。 | - |
<artifactId> | 插件的项目 ID,如 maven-compiler-plugin。 | - |
<version> | 插件版本。 | 建议显式声明,避免使用默认版本。 |
<configuration> | 插件的配置参数,以 XML 形式传递给插件。 | 不同插件支持不同参数。 |
<executions> | 定义插件目标的执行时机(绑定到哪个生命周期阶段)。 | 可覆盖默认绑定。 |
<goals> | 指定要执行的插件目标。 | 如 compile、testCompile。 |
<phase> | 绑定到的生命周期阶段。 | 如 compile、package。 |
插件配置示例(编译插件):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
4.11 资源文件管理(resources)
| 元素名称 | 说明 | 注意事项 |
|---|---|---|
<resources> | 定义主资源文件的来源目录和处理方式。 | 可包含多个 <resource>。 |
<resource> | 一个资源目录的配置。 | 至少包含 <directory>。 |
<directory> | 资源文件所在的目录,默认为 src/main/resources。 | 可指定其他路径。 |
<includes> | 包含的文件模式列表(如 **/*.xml)。 | 若未指定,则包含所有文件。 |
<excludes> | 排除的文件模式列表(如 **/*.txt)。 | 与 <includes> 结合使用进行精细控制。 |
<filtering> | 是否启用资源过滤(替换 ${} 占位符)。 | 设为 true 时,会用 <properties> 中的值替换文件中的占位符。 |
<targetPath> | 资源文件复制到的目标路径(相对于构建输出目录)。 | 默认为根目录。 |
<testResources> | 测试资源的配置,结构与 <resources> 相同。 | 默认目录为 src/test/resources。 |
资源过滤示例:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/application.properties</include>
</includes>
</resource>
</resources>
</build>
application.properties 内容:
db.url=${db.host}:${db.port}/${db.name}
构建时会被替换为 <properties> 中定义的值。
第五章:Maven 依赖管理
5.1 依赖解析机制
| 机制名称 | 说明 | 注意事项 |
|---|---|---|
| 本地仓库查找 | Maven 首先在本地仓库(默认 ~/.m2/repository)中查找依赖的元数据(如 maven-metadata.xml)和构件(JAR 文件)。 | 若存在且版本匹配,则直接使用,无需网络请求。 |
| 中央仓库查询 | 若本地仓库不存在或元数据过期(SNAPSHOT 版本),Maven 会查询远程仓库(默认中央仓库 https://repo.maven.apache.org/maven2/)。 | 可通过 settings.xml 配置镜像(mirror)加速下载。 |
| 依赖传递 | Maven 自动解析依赖的依赖(传递性依赖),构建完整的依赖图。 | 使用 mvn dependency:tree 查看完整依赖树。 |
| SNAPSHOT 版本处理 | 对于 SNAPSHOT 版本,Maven 会检查远程仓库是否有更新(基于时间戳),若有则下载最新快照。 | 可通过 -nsu 或 -U 参数控制更新策略。 |
| POM 解析 | 下载依赖时,不仅下载 JAR,还会下载对应的 POM 文件,以解析其自身的依赖关系。 | 这是实现传递性依赖的基础。 |
| 版本范围支持 | 支持动态版本声明(如 [1.0,2.0)、LATEST、RELEASE),但不推荐在生产项目中使用。 | 动态版本可能导致构建不稳定,建议锁定具体版本。 |
| 依赖冲突检测 | 在解析过程中,Maven 会识别同一库的不同版本,并根据调解原则选择最终版本。 | 冲突可能导致运行时错误,需通过依赖树分析解决。 |
5.2 依赖调解原则
| 原则 | 说明 | 示例 |
|---|---|---|
| 路径最近优先 | 当同一个依赖有多个版本时,选择依赖树中路径最短的那个版本。 | A → B → C(1.0) / A → D → E → C(2.0),选择 C(1.0),因为路径长度为 2 < 4。 |
| 第一声明优先 | 如果依赖路径长度相同,则选择在 pom.xml 中先声明的依赖所引入的传递依赖版本。 | A → B → C(1.0) / A → F → C(2.0),若 B 在 F 之前声明,则选择 C(1.0)。 |
| 依赖管理覆盖 | 在 <dependencyManagement> 中显式声明的版本优先级最高,会强制覆盖传递性依赖的版本。 | 在父 POM 的 dependencyManagement 中声明 log4j 2.17.0,则所有模块都使用此版本。 |
| 作用域影响 | 不同作用域的依赖在不同阶段参与调解。例如,test 作用域依赖不参与运行时类路径构建。 | 编译时只考虑 compile 和 provided;运行时考虑 runtime 和 compile。 |
5.3 依赖作用域详解
| 作用域 | 编译 | 测试 | 运行 | 传递 | 典型用途 | 注意事项 |
|---|---|---|---|---|---|---|
compile | ✅ | ✅ | ✅ | ✅ | 核心业务逻辑(Spring Core, Guava) | 默认作用域,适用于大部分依赖。 |
provided | ✅ | ✅ | ❌ | ✅ | Servlet API, JSP API, Tomcat Embed | 由 JDK 或容器提供,打包时不包含。 |
runtime | ❌ | ✅ | ✅ | ✅ | JDBC Driver (MySQL), Logging Impl (Logback) | 编译时不需要 API,运行时需要实现。 |
test | ❌ | ✅ | ❌ | ❌ | JUnit, Mockito, TestNG | 仅用于测试代码,不打包。 |
system | ✅ | ✅ | ✅ | ✅ | 本地私有 JAR(非 Maven 管理) | 必须用 systemPath 指定路径,破坏可移植性,不推荐。 |
import | - | - | - | - | 引入 BOM(Bill of Materials) | 仅用于 <dependencyManagement>,packaging 必须为 pom。 |
关键区别:
providedvsruntime:provided是编译和测试需要但运行环境已提供;runtime是编译不需要但运行和测试需要。compilevssystem:system依赖必须手动管理 JAR 文件,而compile由 Maven 自动下载。
5.4 使用 dependencyManagement 统一版本管理
| 特性 | 说明 | 注意事项 |
|---|---|---|
| 集中声明 | 在父 POM 的 <dependencyManagement> 中统一定义依赖的 groupId、artifactId 和 version。 | 子模块只需声明 groupId 和 artifactId,自动继承版本。 |
| 版本锁定 | 确保多模块项目中所有模块使用相同版本的依赖,避免版本碎片。 | 是大型项目的最佳实践。 |
| 无实际依赖 | <dependencyManagement> 中的依赖不会被实际引入,除非在 <dependencies> 中声明。 | 仅提供”模板”,不触发下载。 |
| 继承性 | 子模块通过 <parent> 继承父 POM 的 dependencyManagement 配置。 | 多级继承也适用。 |
| BOM 导入 | 使用 import scope 将外部 BOM 的 dependencyManagement 导入。 | 如 Spring Boot: <scope>import</scope><type>pom</type>。 |
父 POM 示例:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>5.3.21</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
</dependencies>
</dependencyManagement>
子模块示例:
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<!-- 无需指定 version,由父 POM 管理 -->
</dependency>
</dependencies>
5.5 查看依赖树(mvn dependency:tree)
| 命令 | 说明 | 输出示例 |
|---|---|---|
mvn dependency:tree | 显示项目完整的依赖树(包括传递性依赖)。 | [INFO] com.example:my-app:jar:1.0-SNAPSHOT → [INFO] +- junit:junit:jar:4.13.2:test → [INFO] \- org.springframework:spring-core:jar:5.3.21:compile |
mvn dependency:tree -Dverbose | 显示更详细信息,包括因冲突被忽略的依赖。 | 会显示 (conflicts with: 2.0) 等提示。 |
mvn dependency:tree -Dincludes=groupId:artifactId | 只显示包含指定坐标的依赖。 | mvn dependency:tree -Dincludes=org.slf4j |
mvn dependency:tree -DExcludes=commons-logging | 排除指定依赖,查看剩余依赖树。 | 用于分析排除后的影响。 |
mvn dependency:tree > tree.txt | 将依赖树输出到文件。 | 便于离线分析或分享。 |
使用场景:
- 排查
ClassNotFoundException或NoSuchMethodError。 - 分析为何某个旧版本库被引入。
- 优化依赖,移除不必要的传递依赖。
5.6 依赖插件常用目标
| 目标 (Goal) | 命令 | 用途 | 注意事项 |
|---|---|---|---|
dependency:analyze | mvn dependency:analyze | 分析项目依赖,报告未使用的直接依赖和未声明的间接依赖。 | 帮助清理 pom.xml,但需谨慎确认”未使用”的依赖是否真的无用。 |
dependency:tree | mvn dependency:tree | 显示依赖树,核心诊断工具。 | 结合 -Dverbose 使用效果更佳。 |
dependency:copy-dependencies | mvn dependency:copy-dependencies | 将所有项目依赖复制到指定目录(默认 target/dependency)。 | 用于创建可分发的依赖包,或离线部署。 |
dependency:get | mvn dependency:get -Dartifact=groupId:artifactId:version | 手动下载单个依赖到本地仓库。 | 调试依赖问题或预加载依赖。 |
dependency:sources | mvn dependency:sources | 下载所有依赖的源码 JAR。 | 便于 IDE 调试时查看第三方库源码。 |
dependency:resolve | mvn dependency:resolve | 仅解析并显示项目直接依赖的坐标。 | 快速查看有哪些直接依赖。 |
dependency:purge-local-repository | mvn dependency:purge-local-repository | 清理本地仓库中的依赖,按需重新下载。 | 解决本地仓库损坏或强制更新 SNAPSHOT。 |
配置示例(在 pom.xml 中预配置 copy-dependencies):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<excludeScope>provided</excludeScope>
</configuration>
</execution>
</executions>
</plugin>
此配置会在 package 阶段自动将依赖复制到 target/lib 目录。
第六章:Maven 构建生命周期与插件
6.1 三套生命周期:default、clean、site
| 生命周期 | 用途 | 独立性 | 核心目标 |
|---|---|---|---|
default | 处理项目部署的核心流程,如编译、测试、打包、安装、部署。 | 是 | compile, test, package, install, deploy |
clean | 清理项目,删除 target/ 目录及构建产物。 | 是 | clean |
site | 生成项目文档站点,包含项目信息、报告、依赖等。 | 是 | site |
关键特性:
- 独立运行: 执行
mvn clean不会触发default生命周期。 - 阶段累积: 执行某个阶段时,会自动按顺序执行之前的所有阶段(如
mvn package会依次执行 validate, compile, test, package)。 - 无相互依赖: 三套生命周期彼此独立,但可在
pom.xml中通过插件绑定实现跨生命周期协作。
6.2 default 生命周期阶段详解
| 阶段 (Phase) | 触发时机 | 主要任务 | 常见插件目标 |
|---|---|---|---|
validate | 构建开始 | 验证项目是否正确,所有必要信息是否可用。 | - |
initialize | 初始化 | 初始化构建状态,如设置属性、创建目录。 | - |
generate-sources | 生成源码前 | 生成编译所需的源代码(如注解处理器、代码生成工具)。 | build-helper-maven-plugin:add-source |
process-sources | 源码处理 | 处理主源码,如资源过滤、替换占位符。 | maven-resources-plugin:resources |
generate-resources | 生成资源前 | 生成编译所需的资源文件。 | - |
process-resources | 资源处理 | 将资源文件复制到输出目录(target/classes),并进行过滤。 | maven-resources-plugin:resources |
compile | 编译 | 编译主源码到字节码(.class 文件)。 | maven-compiler-plugin:compile |
process-classes | 编译后处理 | 对编译后的字节码进行后处理,如字节码增强。 | maven-antrun-plugin:run, aspectj-maven-plugin:compile |
generate-test-sources | 生成测试源码前 | 生成测试所需的源代码。 | - |
process-test-sources | 测试源码处理 | 处理测试源码。 | - |
generate-test-resources | 生成测试资源前 | 生成测试所需的资源文件。 | - |
process-test-resources | 测试资源处理 | 将测试资源复制到测试输出目录(target/test-classes)。 | maven-resources-plugin:testResources |
test-compile | 测试编译 | 编译测试源码。 | maven-compiler-plugin:testCompile |
process-test-classes | 测试编译后处理 | 对测试编译后的字节码进行处理。 | - |
test | 执行测试 | 使用单元测试框架(如 JUnit)运行测试。 | maven-surefire-plugin:test |
prepare-package | 打包准备 | 打包前的准备工作。 | - |
package | 打包 | 将编译后的代码和资源打包成 JAR、WAR 等格式。 | maven-jar-plugin:jar, maven-war-plugin:war |
pre-integration-test | 集成测试前 | 部署包前的准备,如启动数据库、服务器。 | maven-antrun-plugin:run, cargo-maven2-plugin:start |
integration-test | 执行集成测试 | 运行集成测试。 | maven-failsafe-plugin:integration-test |
post-integration-test | 集成测试后 | 清理集成测试环境,如停止服务器。 | maven-antrun-plugin:run, cargo-maven2-plugin:stop |
verify | 验证 | 检查包是否有效,符合质量标准。 | maven-invoker-plugin:run, maven-failsafe-plugin:verify |
install | 安装 | 将包安装到本地仓库,供其他本地项目使用。 | maven-install-plugin:install |
deploy | 部署 | 将包部署到远程仓库(如 Nexus、Artifactory)。 | maven-deploy-plugin:deploy |
说明: 每个阶段本身不执行具体任务,而是由绑定到该阶段的插件目标(Plugin Goal)来执行。
6.3 clean 与 site 生命周期
clean 生命周期
| 阶段 | 说明 | 插件目标 |
|---|---|---|
pre-clean | 清理前执行 | maven-antrun-plugin:run |
clean | 删除 target/ 目录 | maven-clean-plugin:clean |
post-clean | 清理后执行 | maven-antrun-plugin:run |
- 典型命令:
mvn clean(删除构建产物,重新开始)。 - 用途:确保构建环境干净,避免旧文件干扰。
site 生命周期
| 阶段 | 说明 | 插件目标 |
|---|---|---|
pre-site | 站点生成前 | - |
site | 生成项目文档站点 | maven-site-plugin:site |
post-site | 站点生成后 | - |
site-deploy | 部署站点 | maven-site-plugin:deploy |
- 输出目录:
target/site/ - 生成内容:项目信息、依赖报告、测试覆盖率、代码质量报告等。
- 典型命令:
mvn site(生成站点),mvn site-deploy(部署到服务器)。
6.4 插件绑定机制
| 概念 | 说明 | 示例 |
|---|---|---|
| 默认绑定 | Maven 为每种 packaging 类型预定义了插件与生命周期阶段的绑定。 | jar 打包:compile → maven-compiler-plugin:compile / package → maven-jar-plugin:jar |
| 隐式绑定 | 只要使用了某个插件,其默认目标会自动绑定到相应阶段,无需显式配置。 | 添加 maven-compiler-plugin,其 compile 目标自动绑定到 compile 阶段。 |
| 显式绑定 | 在 pom.xml 中通过 <executions> 显式配置插件目标绑定到特定阶段。 | 将 maven-antrun-plugin 绑定到 pre-clean 阶段执行脚本。 |
| 覆盖默认 | 显式配置可以覆盖默认绑定,实现自定义行为。 | 将 maven-compiler-plugin 绑定到 process-sources 阶段提前编译。 |
| 多绑定 | 一个插件目标可绑定到多个阶段,或一个阶段绑定多个插件目标。 | 同一插件在不同阶段执行不同任务。 |
显式绑定配置示例:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>log-start</id>
<phase>initialize</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<echo message="Build started at ${maven.build.timestamp}"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
6.5 常用插件介绍(compiler、surefire、jar、war 等)
| 插件 | GroupId/ArtifactId | 核心目标 | 用途 | 配置要点 |
|---|---|---|---|---|
| Compiler Plugin | org.apache.maven.plugins / maven-compiler-plugin | compile, testCompile | 编译 Java 源码。 | 设置 source 和 target 版本(如 1.8)。 |
| Surefire Plugin | org.apache.maven.plugins / maven-surefire-plugin | test | 执行单元测试(src/test/java)。 | 可配置跳过测试 (skipTests)、包含/排除测试类。 |
| Failsafe Plugin | org.apache.maven.plugins / maven-failsafe-plugin | integration-test, verify | 执行集成测试(src/test/java 中的 *IT 类)。 | 区别于 Surefire,失败时不会中断构建。 |
| Jar Plugin | org.apache.maven.plugins / maven-jar-plugin | jar | 将项目打包为 JAR 文件。 | 可配置 archive(如 manifest, manifestEntries)。 |
| War Plugin | org.apache.maven.plugins / maven-war-plugin | war | 将 Web 项目打包为 WAR 文件。 | 可配置 warSourceDirectory, webXml 等。 |
| Clean Plugin | org.apache.maven.plugins / maven-clean-plugin | clean | 清理 target/ 目录。 | 通常无需配置,开箱即用。 |
| Resources Plugin | org.apache.maven.plugins / maven-resources-plugin | resources, testResources | 复制和过滤资源文件。 | 可配置编码、过滤规则。 |
| Install Plugin | org.apache.maven.plugins / maven-install-plugin | install | 安装构件到本地仓库。 | - |
| Deploy Plugin | org.apache.maven.plugins / maven-deploy-plugin | deploy | 部署构件到远程仓库。 | 需在 settings.xml 配置服务器凭据。 |
| Dependency Plugin | org.apache.maven.plugins / maven-dependency-plugin | copy-dependencies, tree | 分析、复制、管理依赖。 | 用于依赖树分析或打包依赖库。 |
6.6 自定义插件执行配置
| 配置项 | 说明 | 示例 |
|---|---|---|
<executions> | 定义插件的执行配置块,可包含多个执行。 | 一个插件在不同阶段执行不同任务。 |
<execution> | 一个具体的执行实例,包含 id, phase, goals。 | id 用于标识,phase 指定生命周期阶段。 |
<phase> | 绑定到的生命周期阶段。 | compile, package, pre-integration-test。 |
<goals> | 要执行的插件目标列表。 | <goal>jar</goal>, <goal>run</goal>。 |
<configuration> | 插件目标的参数配置,以 XML 形式传递。 | 设置编译版本、文件路径、开关等。 |
<inherited> | 是否被子模块继承(true/false)。 | 通常为 true。 |
<dependencies> | 为插件本身添加依赖(较少用)。 | 为插件提供额外的库支持。 |
综合配置示例(自定义构建流程):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.0.0</version>
<executions>
<!-- 阶段1:编译前打印信息 -->
<execution>
<id>pre-compile-info</id>
<phase>compile</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<echo message="Compiling project ${project.artifactId}..."/>
</target>
</configuration>
</execution>
<!-- 阶段2:打包后复制文件 -->
<execution>
<id>post-package-copy</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<copy file="${project.build.directory}/${project.build.finalName}.jar"
todir="/opt/deploy/apps/"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
第七章:Maven 常用命令
7.1 项目构建相关命令
| 命令 | 说明 | 典型场景 |
|---|---|---|
mvn compile | 编译主源码(src/main/java) | 开发阶段验证代码可编译性 |
mvn test-compile | 编译测试源码(src/test/java) | 检查测试代码语法 |
mvn test | 编译并执行单元测试(使用 Surefire 插件) | 本地运行单元测试,验证功能 |
mvn package | 打包项目(如 JAR/WAR),执行 compile → test → package | 构建可部署的构件 |
mvn clean | 清理 target/ 目录 | 构建前清除旧文件,确保干净环境 |
mvn clean compile | 先清理,再编译 | 确保使用最新代码编译 |
mvn clean package | 清理、编译、测试、打包 | 日常构建或 CI/CD 中常用 |
mvn install | 将包安装到本地仓库(~/.m2/repository) | 供本地其他项目作为依赖使用 |
mvn clean install | 清理、编译、测试、打包、安装 | 开发多模块项目时安装当前模块 |
mvn deploy | 部署到远程仓库(Nexus/Artifactory) | 发布正式版本或快照 |
mvn verify | 执行集成测试和验证 | CI 流水线中质量门禁检查 |
提示:
clean通常与其他命令组合使用,确保构建一致性。
7.2 依赖管理命令
| 命令 | 说明 | 输出示例/用途 |
|---|---|---|
mvn dependency:tree | 显示项目依赖树(含传递性依赖) | 查看所有依赖及其版本,分析冲突 |
mvn dependency:tree -Dverbose | 显示详细依赖树,包含冲突和被忽略的依赖 | 排查 NoSuchMethodError 等版本冲突问题 |
mvn dependency:tree -Dincludes=org.slf4j | 只显示包含 org.slf4j 的依赖 | 快速定位特定库的引入路径 |
mvn dependency:tree -DExcludes=commons-logging | 排除 commons-logging,查看剩余依赖 | 分析排除后的影响 |
mvn dependency:analyze | 分析依赖使用情况 | 报告未使用的依赖(Used undeclared)和未声明的依赖(Unused declared) |
mvn dependency:copy-dependencies | 将所有依赖复制到 target/dependency | 创建可分发的依赖包 |
mvn dependency:sources | 下载所有依赖的源码 | 便于在 IDE 中调试第三方库 |
mvn dependency:resolve | 解析并列出项目直接依赖 | 快速查看 pom.xml 中声明的依赖 |
实用技巧:
- 将
dependency:tree输出重定向到文件:mvn dependency:tree > deps.txt - 结合
grep过滤:mvn dependency:tree | grep 'spring-core'
7.3 插件执行命令
| 命令 | 说明 | 插件目标 | 用途 |
|---|---|---|---|
mvn compiler:compile | 直接调用编译插件编译主代码 | maven-compiler-plugin:compile | 跳过生命周期,直接编译 |
mvn surefire:test | 执行单元测试 | maven-surefire-plugin:test | 仅运行测试,不打包 |
mvn failsafe:integration-test | 执行集成测试 | maven-failsafe-plugin:integration-test | 运行 *IT.java 测试类 |
mvn failsafe:verify | 验证集成测试结果 | maven-failsafe-plugin:verify | 检查测试是否通过 |
mvn jar:jar | 打包 JAR 文件 | maven-jar-plugin:jar | 手动触发打包 |
mvn war:war | 打包 WAR 文件 | maven-war-plugin:war | Web 项目打包 |
mvn antrun:run | 执行 Ant 任务 | maven-antrun-plugin:run | 自定义构建脚本(需配置) |
mvn site:site | 生成项目文档站点 | maven-site-plugin:site | 生成项目报告和文档 |
mvn versions:display-dependency-updates | 显示依赖的可用更新 | versions-maven-plugin:display-dependency-updates | 检查依赖是否过时(需添加插件) |
注意: 直接调用插件目标时,不会自动执行生命周期的前置阶段。例如
mvn compiler:compile不会自动执行generate-sources。
7.4 项目信息查看命令
| 命令 | 说明 | 输出内容 |
|---|---|---|
mvn help:effective-pom | 显示实际生效的 POM(合并了父 POM 和 profile) | 查看最终使用的配置,调试继承问题 |
mvn help:effective-settings | 显示实际生效的 Settings(合并 settings.xml) | 查看仓库、代理、服务器等配置 |
mvn help:describe -Dplugin=compiler | 描述指定插件的信息 | 显示插件目标、参数、默认绑定阶段 |
mvn help:describe -Dplugin=compiler -Dgoal=compile | 描述插件的特定目标 | 查看 compiler:compile 的详细参数 |
mvn validate | 验证项目 POM 是否正确 | 检查 pom.xml 语法和结构 |
mvn --version 或 mvn -v | 显示 Maven 版本、Java 版本、操作系统信息 | 环境诊断 |
mvn archetype:generate | 创建新项目骨架 | 交互式选择模板生成项目 |
调试技巧:
- 使用
effective-pom查看<dependencyManagement>是否正确继承。 - 使用
effective-settings确认是否使用了正确的镜像仓库。
7.5 多模块项目命令执行
| 场景 | 命令 | 说明 |
|---|---|---|
| 在根模块执行 | mvn clean install | 构建所有模块,按依赖顺序安装到本地仓库 |
| 构建指定模块 | mvn install -pl module-name | 只构建 module-name 模块 |
| 构建模块及依赖 | mvn install -pl module-name -am | 构建 module-name 及其直接依赖的模块(Aggregator Mode) |
| 构建模块及被依赖 | mvn install -pl module-name -amd | 构建 module-name 及依赖它的模块(Also Make Dependents) |
| 跳过测试 | mvn install -DskipTests | 安装所有模块,跳过测试执行 |
| 跳过特定模块 | mvn install -pl !module-to-skip | 排除某个模块(Maven 3.2.1+) |
| 并行构建 | mvn -T 4 clean install | 使用 4 个线程并行构建,加速多模块项目 |
| 仅构建反应堆中的模块 | mvn install --also-make | 与 -am 类似,构建指定模块的依赖 |
| 查看构建顺序 | mvn help:reactor | 显示模块的构建顺序(反应堆顺序) |
反应堆(Reactor): Maven 根据模块间的依赖关系计算出的构建顺序。
示例项目结构:
parent/
├── module-a (依赖 module-common)
├── module-b (依赖 module-a)
└── module-common
mvn install -pl module-b -am:构建顺序为module-common→module-a→module-bmvn install -pl module-common -amd:构建顺序为module-common→module-a→module-b
第八章:仓库管理与私服
8.1 本地仓库结构解析
| 特性 | 说明 | 示例路径 |
|---|---|---|
| 默认位置 | 用户主目录下的 .m2/repository | C:\Users\YourName\.m2\repository (Windows) / /home/yourname/.m2/repository (Linux/macOS) |
| 目录结构 | 按 groupId 分层创建目录,artifactId 为子目录,version 为最内层 | com/example/my-app/1.0.0/ |
| 存储内容 | 构件文件(JAR, WAR, POM) / 元数据文件(maven-metadata.xml) / 校验文件(.sha1, .md5) | my-app-1.0.0.jar / my-app-1.0.0.pom / maven-metadata-local.xml |
| SNAPSHOT 版本 | 存储带时间戳和构建号的文件,便于管理快照更新 | my-app-1.0.0-20231001.123456-1.jar |
| 作用 | 缓存远程下载的依赖 / 存储本地 install 的构件 / 供多项目共享依赖 | 避免重复下载,提升构建速度 |
| 配置方式 | 在 settings.xml 中通过 <localRepository> 指定 | <settings><localRepository>/opt/maven/repo</localRepository></settings> |
关键点:
- 本地仓库是 Maven 构建的第一查找源。
- 删除本地仓库中某个构件目录,可强制 Maven 重新下载(解决损坏依赖)。
- 多用户系统中,每个用户有独立的本地仓库。
8.2 远程仓库配置(repositories)
| 特性 | 说明 | 配置位置 |
|---|---|---|
| 定义 | 指定 Maven 从哪些远程服务器下载依赖。 | pom.xml 或 settings.xml |
| 默认仓库 | Maven 默认使用中央仓库(https://repo.maven.apache.org/maven2) | 无需配置 |
| 私有仓库 | 企业内部仓库,存放私有构件或代理外部依赖。 | 需手动配置 |
| 配置方式 | 使用 <repositories> 和 <repository> 元素 | pom.xml 中声明 |
| ID 唯一性 | 每个仓库必须有唯一 id | 用于 settings.xml 中匹配服务器信息 |
| 布局 | 通常为 default(Maven 2/3 标准布局) | <layout>default</layout> |
| 启用/禁用 | 可通过 <enabled> 控制仓库是否激活 | 默认 true |
pom.xml 配置示例:
<repositories>
<repository>
<id>company-internal</id>
<name>Company Internal Repository</name>
<url>https://nexus.company.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
注意事项:
- 在
pom.xml中配置仓库会影响所有使用该项目的构建。 - 推荐在
settings.xml中通过镜像统一管理,而非在pom.xml中硬编码。
8.3 镜像仓库配置(mirrors)
| 特性 | 说明 | 配置位置 |
|---|---|---|
| 定义 | 将对某个仓库的请求重定向到镜像仓库,实现透明代理。 | settings.xml |
| 用途 | 加速依赖下载(如使用阿里云镜像)/ 统一企业内部仓库入口 / 隔离外部网络风险 | 提升构建效率与安全性 |
| 匹配规则 | 通过 <mirrorOf> 指定匹配的仓库 id | 支持通配符 |
| 常用值 | *:镜像所有仓库 / central:仅镜像中央仓库 / external:*:镜像所有外部仓库 | 灵活控制范围 |
| 身份验证 | 镜像仓库的认证信息在 <servers> 中配置 | 与仓库 id 对应 |
settings.xml 配置示例:
<settings>
<mirrors>
<!-- 阿里云 Maven 镜像,加速下载 -->
<mirror>
<id>aliyunmaven</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Maven</name>
<url>https://maven.aliyun.com/repository/central</url>
</mirror>
<!-- 镜像所有仓库到企业 Nexus -->
<mirror>
<id>nexus-mirror</id>
<mirrorOf>*</mirrorOf>
<name>Internal Nexus Mirror</name>
<url>https://nexus.company.com/repository/maven-all/</url>
</mirror>
</mirrors>
<!-- 服务器认证信息 -->
<servers>
<server>
<id>nexus-mirror</id>
<username>deploy</username>
<password>secret</password>
</server>
</servers>
</settings>
最佳实践:
- 开发团队统一使用
settings.xml配置镜像,避免在pom.xml中分散配置。 - 使用
*镜像时,无需在pom.xml中配置repositories。
8.4 私服(Nexus / Artifactory)简介
| 特性 | Nexus (Sonatype) | Artifactory (JFrog) | 说明 |
|---|---|---|---|
| 类型 | 仓库管理器 | 通用制品仓库 | 两者均支持 Maven、Docker、npm 等 |
| 架构 | Java Web 应用(War/Jar) | Java 应用 | 可部署在 Tomcat 或独立运行 |
| 核心功能 | 代理远程仓库(Proxy)/ 存储内部构件(Hosted)/ 聚合仓库组(Group) | 企业级依赖管理核心 | - |
| 仓库类型 | Proxy, Hosted, Group | Local, Remote, Virtual | 实现统一访问入口 |
| 访问控制 | 基于角色的权限管理(RBAC) | 细粒度权限控制 | 控制谁可以读/写哪些仓库 |
| 高可用 | 支持集群(Nexus Pro) | 原生支持集群 | 保障生产环境稳定 |
| UI 界面 | Web 管理界面 | 功能丰富的 Web UI | 方便浏览和搜索构件 |
| 搜索功能 | 支持按 GAV 搜索 | 高级搜索(元数据、内容) | 快速定位依赖 |
| 社区版 | Nexus OSS(开源) | Artifactory Community Edition | 免费使用,功能有限 |
| 企业版 | Nexus Pro(收费) | Artifactory Enterprise(收费) | 提供高级功能(安全、审计、CI 集成) |
典型部署架构:
Developer → settings.xml (Mirror) → Nexus/Artifactory
↓
(Proxy) → Central Repository (Internet)
(Hosted) → Internal Libraries (e.g., company-utils)
所有依赖请求通过私服,私服负责缓存和分发。
8.5 部署构件到远程仓库(mvn deploy)
| 步骤 | 说明 | 配置/命令 |
|---|---|---|
| 1. 配置发布仓库 | 在 pom.xml 中指定 distributionManagement | 见下方示例 |
| 2. 配置认证信息 | 在 settings.xml 的 <servers> 中配置用户名密码 | 见下方示例 |
| 3. 执行部署命令 | 使用 mvn deploy 部署构件 | mvn clean deploy |
| 4. 版本控制 | version 不含 SNAPSHOT → 发布到 repository / version 含 SNAPSHOT → 发布到 snapshotRepository | 自动识别 |
| 5. 部署内容 | 主构件(JAR/WAR)、POM 文件、源码(sources)、Javadoc(javadoc)、校验文件(SHA1, MD5) | 可通过插件生成 |
| 6. 权限要求 | internal-release 仓库通常禁止重复部署相同版本 / internal-snapshot 允许覆盖 | 防止版本污染 |
| 7. 常用参数 | -DskipTests:跳过测试 / -Dmaven.source.skip=true:跳过源码 / -DaltDeploymentRepository:临时指定部署仓库 | 灵活控制部署行为 |
pom.xml 配置示例:
<distributionManagement>
<repository>
<id>internal-release</id>
<url>https://nexus.company.com/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>internal-snapshot</id>
<url>https://nexus.company.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
settings.xml 认证配置:
<servers>
<server>
<id>internal-release</id>
<username>deploy</username>
<password>release-pass</password>
</server>
<server>
<id>internal-snapshot</id>
<username>deploy</username>
<password>snapshot-pass</password>
</server>
</servers>
部署流程:
- Maven 读取
pom.xml中的distributionManagement。 - 根据
version判断是 Release 还是 Snapshot。 - 查找
settings.xml中对应id的服务器凭据。 - 将构件上传到指定仓库。
注意事项:
- 确保
settings.xml中的server.id与pom.xml中的repository.id完全一致。 - 部署 Release 版本前,确保代码经过充分测试。
- 私服通常配置为拒绝 SNAPSHOT 版本进入 Release 仓库。
第九章:多模块项目管理
9.1 聚合项目(Aggregator)配置
| 特性 | 说明 | 配置方式 |
|---|---|---|
| 定义 | 聚合项目(也称反应堆项目)用于将多个模块组织在一起,统一构建。 | 在 pom.xml 中使用 <modules> 元素 |
| 核心作用 | 统一执行构建命令(如 mvn clean install)/ 按依赖顺序自动构建模块 | 简化多模块管理 |
| POM 类型 | 聚合项目的 packaging 必须为 pom | <packaging>pom</packaging> |
| 模块声明 | 通过 <modules> 列出所有子模块的相对路径 | 路径相对于聚合 POM |
| 灵活性 | 子模块可以位于任意目录层级,不要求必须在子目录中 | 支持非标准布局 |
| 构建顺序 | Maven 自动计算模块间的依赖关系,确定构建顺序(反应堆顺序) | 无需手动指定 |
聚合 POM 示例(pom.xml):
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<!-- 声明子模块 -->
<modules>
<module>common</module> <!-- 子目录 common/ -->
<module>service</module> <!-- 子目录 service/ -->
<module>webapp</module> <!-- 子目录 webapp/ -->
<module>../shared-utils</module> <!-- 上级目录的模块 -->
</modules>
</project>
关键点:
- 聚合是”自上而下”的,由父 POM 控制构建哪些模块。
- 在聚合项目的根目录执行
mvn命令,会自动应用到所有声明的模块。
9.2 继承机制(Parent POM)
| 特性 | 说明 | 配置方式 |
|---|---|---|
| 定义 | 子模块继承父 POM 的配置,实现配置复用和统一管理。 | 子模块中使用 <parent> 元素 |
| 核心作用 | 统一版本管理(dependencyManagement)/ 统一插件配置 / 定义公共属性 | 避免配置重复 |
| POM 层级 | 支持多级继承(Grand Parent → Parent → Child) | 配置可层层传递 |
| 继承内容 | 大部分 POM 元素均可继承,包括:groupId, version / dependencies, dependencyManagement / properties / build/plugins | 子模块可覆盖 |
| 父 POM 位置 | 通常与子模块在同一项目中(相对路径)或在远程仓库 | 使用 <relativePath> 指定 |
| 强制继承 | 子模块必须声明 <parent> 才能继承 | 显式关系 |
父 POM 示例(parent/pom.xml):
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<!-- 统一依赖版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.21</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 统一插件配置 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
子模块继承示例(webapp/pom.xml):
<project>
<modelVersion>4.0.0</modelVersion>
<!-- 继承父 POM -->
<parent>
<groupId>com.example</groupId>
<artifactId>my-parent</artifactId>
<version>1.0.0</version>
<relativePath>../parent/pom.xml</relativePath> <!-- 相对路径 -->
</parent>
<artifactId>webapp</artifactId>
<!-- groupId 和 version 从父 POM 继承 -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<!-- 无需指定 version,由父 POM 的 dependencyManagement 管理 -->
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!-- scope 也从 dependencyManagement 继承 -->
</dependency>
</dependencies>
</project>
关键点:
- 继承是”自下而上”的,子模块主动声明继承关系。
- 使用
mvn help:effective-pom可查看最终生效的完整配置。
9.3 聚合与继承的结合使用
| 模式 | 说明 | 典型结构 | 优势 |
|---|---|---|---|
| 聚合与继承分离 | 聚合 POM 和父 POM 是两个独立的项目。 | 见下方示例 | 灵活性高 / 父 POM 可被多个项目复用 |
| 聚合与继承合一 | 聚合 POM 同时作为父 POM。 | 见下方示例 | 结构简单 / 配置集中 / 最常用模式 |
分离模式典型结构:
root/
├── aggregator-pom.xml (packaging=pom, <modules>)
├── parent/
│ └── pom.xml (packaging=pom, <dependencyManagement>)
├── module-a/
│ └── pom.xml (<parent> 指向 parent)
└── module-b/
└── pom.xml (<parent> 指向 parent)
合一模式示例(root/pom.xml):
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<!-- 既是聚合器,也是父 POM -->
<modules>
<module>common</module>
<module>service</module>
<module>webapp</module>
</modules>
<!-- 统一配置 -->
<dependencyManagement>...</dependencyManagement>
<build>...</build>
</project>
最佳实践:
- 对于单一项目,推荐使用”合一”模式,简单高效。
- 对于多个相关项目共享同一套配置,可使用”分离”模式,提高父 POM 复用性。
9.4 模块间依赖管理
| 场景 | 配置方式 | 说明 | 注意事项 |
|---|---|---|---|
| 模块间依赖 | 在子模块的 <dependencies> 中声明对其他模块的依赖。 | 见下方示例 | Maven 会自动构建依赖的模块(如果在反应堆中)/ 依赖的模块必须在 dependencyManagement 中声明或版本一致 |
| 版本管理 | 通过父 POM 的 <dependencyManagement> 统一管理所有模块的版本。 | 见下方示例 | 使用 ${project.version} 确保所有模块版本同步 / 避免版本碎片 |
| 循环依赖 | 必须避免。Maven 无法构建存在循环依赖的模块。 | A → B → A ❌ | - |
| 依赖范围 | 可使用 test、provided 等范围控制依赖传递。 | 如 Web 模块 provided Servlet API | - |
| 可选依赖 | 使用 <optional>true</optional> 声明可选依赖,不传递给下游。 | 适用于功能扩展模块 | - |
模块间依赖声明示例(在 webapp 模块中依赖 service 模块):
<dependency>
<groupId>com.example</groupId>
<artifactId>service</artifactId>
<version>1.0.0</version> <!-- 通常从父 POM 继承 -->
</dependency>
版本管理示例(在父 POM 中):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version> <!-- 使用项目版本 -->
</dependency>
</dependencies>
</dependencyManagement>
构建顺序: Maven 会根据依赖关系自动排序:
common(无内部依赖)service(依赖common)webapp(依赖service)
9.5 多模块构建策略
| 策略 | 命令 | 说明 | 适用场景 |
|---|---|---|---|
| 全量构建 | mvn clean install | 构建所有模块,从根目录执行。 | 初始构建、CI/CD 流水线 |
| 增量构建 | mvn install | 跳过 clean,仅重新编译变更的模块。 | 日常开发,节省时间 |
| 并行构建 | mvn -T 4 clean install | 使用 4 个线程并行构建模块。 | 多核机器,加速构建 |
| 聚焦构建 | mvn install -pl webapp | 仅构建 webapp 模块。 | 只修改了某个模块 |
| 构建模块及依赖 | mvn install -pl webapp -am | 构建 webapp 及其依赖的模块(如 service, common)。 | 修改了 webapp,需确保依赖是最新的 |
| 构建模块及被依赖 | mvn install -pl common -amd | 构建 common 及依赖它的模块(如 service, webapp)。 | 修改了公共库,需验证所有下游 |
| 跳过测试 | mvn install -DskipTests | 安装所有模块,跳过测试执行。 | 快速安装到本地仓库 |
| 跳过特定模块 | mvn install -pl !legacy-module | 排除 legacy-module 模块。 | 临时跳过有问题的模块 |
| 离线构建 | mvn install -o | 仅使用本地仓库,不访问网络。 | 无网络环境或确保稳定性 |
| 反应堆分析 | mvn help:reactor | 显示模块的构建顺序和依赖关系。 | 调试构建流程 |
最佳实践:
- 开发阶段: 使用
-pl和-am/-amd精准构建,提高效率。 - CI/CD 环境: 使用
-T 1C(每核一线程)实现最优并行性能。 - 发布版本: 务必执行完整测试(
mvn clean deploy),避免跳过测试。 - 依赖管理: 始终通过
dependencyManagement统一版本,避免冲突。
第十章:Maven 高级特性
10.1 属性与资源过滤
| 特性 | 说明 | 示例 |
|---|---|---|
| 属性(Properties) | 定义可重用的变量,用于配置复用。 | <properties><app.version>1.0</app.version></properties> |
| 内置属性 | Maven 预定义的属性。 | ${basedir}(项目根目录) / ${version}(项目版本) / ${project.basedir}(同 basedir) |
| POM 属性 | 引用 POM 文件中的元素。 | ${project.groupId} / ${project.artifactId} / ${project.version} |
| 系统属性 | JVM 系统属性或环境变量。 | ${java.home} / ${env.HOME} / ${env.PATH} |
| 自定义属性 | 在 <properties> 中定义。 | <my.property>value</my.property> → ${my.property} |
| Settings 属性 | 引用 settings.xml 中的值。 | ${settings.localRepository} |
| 资源过滤(Resource Filtering) | 在复制资源文件时,替换文件中的 ${} 占位符为属性值。 | 将 application.properties 中的 ${db.url} 替换为实际值 |
| 启用过滤 | 在 maven-resources-plugin 配置中设置 <filtering>true</filtering>。 | 见下方示例 |
| 过滤文件 | 通过 <filters> 指定属性文件(.properties 或 .xml)。 | 见下方示例 |
| 典型应用 | 多环境配置(dev/test/prod)/ 动态版本信息注入 / 构建时间戳 | 见下方示例 |
启用资源过滤:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
指定过滤文件:
<build>
<filters>
<filter>config/${env}.properties</filter>
</filters>
</build>
典型应用示例 - application.properties:
app.version=${project.version}
build.time=${maven.build.timestamp}
db.url=${db.url}
构建时间戳格式: 可通过 maven.build.timestamp.format 属性自定义。
<properties>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
</properties>
10.2 构建配置文件(Profiles)
| 特性 | 说明 | 配置位置 |
|---|---|---|
| 定义 | 根据不同条件激活不同的构建配置。 | pom.xml 或 settings.xml |
| 激活方式 | 默认激活:<activeByDefault>true</activeByDefault> / 条件激活:基于属性、JDK、操作系统、文件存在等 / 显式激活:命令行 -Pprofile-name | 灵活控制 |
| 配置内容 | 可覆盖或添加:依赖、插件、属性、资源目录、模块 | 实现差异化构建 |
| 作用域 | pom.xml:影响当前项目 / settings.xml:影响所有构建(全局) | 通常 pom.xml 更常见 |
| ID 唯一性 | 每个 Profile 必须有唯一 id。 | 用于命令行激活 |
pom.xml 中 Profile 示例:
<profiles>
<!-- 开发环境 Profile -->
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>development</env>
<db.url>jdbc:h2:mem:testdb</db.url>
</properties>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</profile>
<!-- 生产环境 Profile -->
<profile>
<id>prod</id>
<properties>
<env>production</env>
<db.url>jdbc:postgresql://prod-db:5432/app</db.url>
</properties>
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
</dependencies>
</profile>
<!-- 基于 JDK 激活 -->
<profile>
<id>jdk-11</id>
<activation>
<jdk>11</jdk>
</activation>
<properties>
<maven.compiler.release>11</maven.compiler.release>
</properties>
</profile>
</profiles>
激活命令:
mvn compile -Pdev:显式激活 dev Profilemvn compile:默认激活 dev(因activeByDefault)mvn compile -Pprod:激活 prod Profile
最佳实践:
- 避免在
settings.xml中定义业务相关的 Profile。 - 使用 Profile 实现环境隔离,而非在代码中硬编码。
10.3 多环境构建支持
| 方法 | 说明 | 实现方式 |
|---|---|---|
| Profile + 属性过滤 | 最常用、最灵活的方式。 | 1. 定义多个 Profile(dev/test/prod) 2. 每个 Profile 设置不同属性(如 env)3. 资源文件使用 ${} 占位符4. 启用资源过滤 |
| 多套资源目录 | 为不同环境创建独立的资源目录。 | 见下方示例 |
| Profile 专属资源 | 在 Profile 中覆盖资源目录。 | 见下方示例 |
| 外部配置文件 | 构建时指定外部属性文件。 | mvn install -Denv=prod,结合 <filters><filter>config-${env}.properties</filter></filters> |
多套资源目录配置:
<build>
<resources>
<resource>
<directory>src/main/resources-${env}</directory>
</resource>
</resources>
</build>
Profile 专属资源配置:
<profile>
<id>prod</id>
<build>
<resources>
<resource>
<directory>src/main/resources-prod</directory>
</resource>
</resources>
</build>
</profile>
完整示例流程:
创建配置文件:
src/main/filters/dev.properties:
db.url=jdbc:h2:mem:devdb
logging.level=DEBUG
src/main/filters/prod.properties:
db.url=jdbc:postgresql://prod-db/app
logging.level=WARN
配置 POM:
<profiles>
<profile>
<id>dev</id>
<activation><activeByDefault>true</activeByDefault></activation>
<properties><env>dev</env></properties>
</profile>
<profile>
<id>prod</id>
<properties><env>prod</env></properties>
</profile>
</profiles>
<build>
<filters>
<filter>src/main/filters/${env}.properties</filter>
</filters>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
构建命令:
mvn clean package→ 使用 dev 配置mvn clean package -Pprod→ 使用 prod 配置
10.4 可重复构建与版本管理
| 特性 | 说明 | 实践方法 |
|---|---|---|
| 可重复构建(Reproducible Builds) | 相同的源码和依赖,在不同时间、不同机器上构建出完全相同的二进制文件。 | 固定所有依赖版本(避免 LATEST, RELEASE)/ 使用 dependencyManagement 统一管理 / 确保构建环境一致(JDK、Maven 版本)/ 避免使用时间戳(或固定时间戳) |
| 版本锁定 | 确保依赖版本不因中央仓库更新而改变。 | 使用 dependencyManagement / 使用 maven-enforcer-plugin 强制规则 / 使用 BOM(Bill of Materials) |
| BOM(物料清单) | 一种特殊的 POM,只包含 dependencyManagement,用于统一管理依赖版本。 | Spring Boot 的 spring-boot-dependencies |
| 使用 BOM | 在 dependencyManagement 中导入 BOM。 | 见下方示例 |
| 构建时间戳 | 默认时间戳影响可重复性。 | 设置固定时间戳或使用 SOURCE_DATE_EPOCH 环境变量 |
| 确定性构建 | Maven 3.6.1+ 支持更严格的可重复构建。 | 参考 Reproducible Build Maven Plugin |
BOM 导入示例:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
版本管理最佳实践:
- 主版本(1.0.0)、次版本(1.1.0)、增量版本(1.0.1)语义化。
- SNAPSHOT 版本用于开发中,Release 版本用于生产。
- 使用
mvn versions:set插件批量更新版本。
10.5 使用 Maven 进行发布(mvn release:prepare 等)
| 阶段 | 命令 | 说明 | 自动执行的操作 |
|---|---|---|---|
| 准备发布 | mvn release:prepare | 准备发布一个正式版本。 | 1. 运行 clean 和 verify2. 提示输入 Release 版本号(如 1.0.0) 3. 提示输入下一个开发版本号(如 1.0.1-SNAPSHOT) 4. 更新所有 pom.xml 中的版本5. 提交更改并打 Git Tag(如 v1.0.0) 6. 提交版本更新 |
| 执行发布 | mvn release:perform | 执行发布,将构件部署到远程仓库。 | 1. 检出 release:prepare 创建的 Tag2. 执行 mvn deploy3. 将 Release 构件(JAR/POM)上传到远程仓库 |
| 回滚发布 | mvn release:rollback | 如果 release:prepare 失败,回滚到之前状态。 | 恢复 pom.xml 版本和提交 |
| 清理发布 | mvn release:clean | 清理 release 插件生成的临时文件(如 release.properties)。 | 删除 release.properties, backup pom.xml 等 |
| 跳过测试 | mvn release:prepare -Darguments="-DskipTests" | 在准备阶段跳过测试。 | 谨慎使用,仅用于快速迭代 |
| 非交互模式 | mvn release:prepare -B -DautoVersionSubmodules=true | 自动化发布(CI/CD)。 | -B:批处理模式 / -DautoVersionSubmodules:自动推导子模块版本 |
release 插件配置(pom.xml):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<tagNameFormat>v@{project.version}</tagNameFormat> <!-- Tag 格式 -->
<autoVersionSubmodules>true</autoVersionSubmodules> <!-- 自动版本 -->
<useReleaseProfile>false</useReleaseProfile> <!-- 不使用内置 release profile -->
<goals>deploy</goals> <!-- 执行 deploy -->
</configuration>
</plugin>
</plugins>
</build>
发布流程:
- 确保代码在 main 分支,无未提交更改。
- 执行
mvn release:prepare→ 生成 v1.0.0 Tag,代码回到 1.0.1-SNAPSHOT。 - 执行
mvn release:perform→ 部署 1.0.0 版本到 Nexus。 - (可选)执行
mvn release:clean清理。
注意事项:
- 发布前确保
distributionManagement配置正确。 - 发布的版本号不可覆盖,一旦发布失败需升级版本重试。
- release 插件依赖 Git/SVN,确保版本控制正常。
第十一章:常见问题与最佳实践
11.1 常见错误与解决方案
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
Could not resolve dependencies | 依赖在仓库中不存在 / 仓库 URL 配置错误 / 网络问题(代理/防火墙) / 认证失败(私服需要登录) | 1. 检查 pom.xml 中 groupId, artifactId, version 是否正确2. 使用 mvn dependency:tree 查看依赖来源3. 检查 settings.xml 中 repositories 和 mirrors 配置4. 验证网络连接和代理设置 5. 确认 settings.xml 的 <servers> 中有正确凭据 |
Plugin execution not covered by lifecycle configuration (Eclipse) | IDE 未识别插件的生命周期绑定。 | 1. 在 Eclipse 中右键项目 → Maven → Update Project 2. 或安装 m2e 连接器(m2e-connectors) 3. 在 pom.xml 中添加 <pluginManagement> 配置 |
Non-resolvable parent POM | 找不到父 POM。 | 1. 检查 <parent> 的 groupId, artifactId, version2. 检查 <relativePath> 是否正确(默认 ../pom.xml)3. 确保父 POM 已 install 到本地仓库或在项目结构中 |
Build failure: Failed to clean project | target/ 目录被占用(如 IDE、进程锁定)。 | 1. 关闭占用文件的程序(如 IDE、命令行) 2. 重启 IDE 或计算机 3. 手动删除 target/ 目录 |
OutOfMemoryError during build | Maven 内存不足。 | 设置环境变量:export MAVEN_OPTS="-Xms512m -Xmx2048m" |
The goal you specified requires a project to execute | 在非项目目录执行 mvn 命令。 | 确保在包含 pom.xml 的目录执行命令 |
| SNAPSHOT dependency has newer version | 本地 SNAPSHOT 版本过期。 | 执行 mvn clean compile -U 强制更新快照依赖 |
通用排查步骤:
- 阅读错误日志:从最后一行向上查找 ERROR 或
Caused by。 - 清理重建:
mvn clean compile。 - 检查配置:
pom.xml和settings.xml。 - 搜索社区:Stack Overflow、Maven 官方文档。
11.2 依赖冲突排查
| 方法 | 命令/工具 | 说明 |
|---|---|---|
| 依赖树分析 | mvn dependency:tree | 查看所有依赖及其传递路径,定位冲突来源。 |
| 详细依赖树 | mvn dependency:tree -Dverbose | 显示被忽略的依赖(因冲突被仲裁),关键诊断工具。 |
| 过滤特定依赖 | mvn dependency:tree -Dincludes=org.slf4j:slf4j-api | 快速定位 slf4j-api 的引入情况。 |
| 分析依赖使用 | mvn dependency:analyze | 报告:Used undeclared dependencies(代码使用但未声明的依赖)/ Unused declared dependencies(声明了但未使用的依赖) |
| 查看生效 POM | mvn help:effective-pom | 确认最终使用的 <dependencyManagement> 和依赖版本。 |
| IDE 支持 | IntelliJ IDEA / Eclipse Maven 插件 | 图形化查看依赖树,高亮冲突。 |
冲突解决策略:
-
版本仲裁: Maven 默认使用”最近定义”原则(依赖树中路径最短的优先)。
-
依赖排除: 排除传递性依赖中的冲突版本。
<dependency>
<groupId>com.example</groupId>
<artifactId>module-a</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
- 依赖管理: 在
dependencyManagement中主动声明期望的版本。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>
</dependencyManagement>
- 统一 BOM: 引入企业级或框架的 BOM 来管理版本。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
典型冲突场景:
NoSuchMethodError/ClassNotFoundException:通常是版本不匹配。- 日志框架混乱(SLF4J + Log4j + JUL):排除不必要的绑定。
11.3 构建性能优化
| 优化策略 | 实现方式 | 效果 |
|---|---|---|
| 并行构建 | mvn -T 4 clean install 或 mvn -T 1C clean install | 利用多核 CPU,显著提升多模块构建速度。1C 表示每核一个线程。 |
| 跳过测试 | mvn install -DskipTests 或 mvn install -Dmaven.test.skip=true | 跳过测试编译和执行(后者连编译都跳过),大幅提升构建速度。 |
| 离线模式 | mvn install -o | 不访问远程仓库,仅使用本地缓存,避免网络延迟。 |
| 增量构建 | 避免不必要的 clean | mvn compile 仅编译变更文件,比 mvn clean compile 快。 |
| 使用镜像仓库 | 在 settings.xml 配置阿里云或企业 Nexus 镜像 | 大幅加速依赖下载。 |
| 依赖预下载 | mvn dependency:go-offline | 预先下载所有依赖,确保后续构建离线可用。 |
| 配置构建环境 | 设置 MAVEN_OPTS | export MAVEN_OPTS="-Xms512m -Xmx2g -XX:ReservedCodeCacheSize=512m" 防止 OOM。 |
| 减少依赖 | 使用 dependency:analyze 移除未使用依赖 | 减少传递性依赖数量,缩短依赖解析时间。 |
| 使用最新 Maven | 升级到 Maven 3.8+ | 新版本在依赖解析和性能上有优化。 |
| CI/CD 优化 | 启用构建缓存(如 GitHub Actions, Jenkins Pipeline)/ 复用 Docker 镜像中的本地仓库 | 避免重复下载依赖。 |
最佳实践:
- 开发时: 使用
-pl和-am精准构建相关模块。 - CI/CD: 结合并行构建、镜像仓库和构建缓存。
11.4 安全性配置(密码加密等)
| 安全风险 | 解决方案 | 配置方法 |
|---|---|---|
| 明文密码 | settings.xml 中的仓库密码明文存储。 | 使用 Maven 密码加密功能。 |
| 加密主密码 | 1. 生成主密码(Master Password) 2. 用主密码加密服务器密码 | 见下方示例 |
settings-security.xml | 存储加密的主密码。 | 见下方示例 |
settings.xml | 使用加密后的密码。 | 见下方示例 |
| 凭证管理 | 避免在 pom.xml 或 settings.xml 中硬编码凭证。 | 使用 CI/CD 系统的 Secret 管理(如 GitHub Secrets, Jenkins Credentials)/ 构建时通过环境变量注入 |
| 依赖安全扫描 | 使用已知漏洞的第三方库。 | 集成 OWASP Dependency-Check 插件 |
| 最小权限原则 | 仓库账号权限过大。 | 为 deploy 账号仅分配 releases 仓库的写权限,snapshots 仓库的读写权限。 |
生成主密码:
# 生成主密码(存储在 ~/.m2/settings-security.xml)
mvn --encrypt-master-password your-master-password
settings-security.xml 示例:
<settingsSecurity>
<master>{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+44nILF95/s=}</master>
</settingsSecurity>
加密服务器密码:
# 加密服务器密码
mvn --encrypt-password your-server-password
settings.xml 使用加密密码:
<servers>
<server>
<id>nexus-releases</id>
<username>deploy</username>
<password>{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+44nILF95/s=}</password>
</server>
</servers>
OWASP Dependency-Check 插件配置:
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.2.1</version>
<executions>
<execution>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>
重要提示:
- 主密码是解密所有服务器密码的关键,务必妥善保管。
- 在 CI/CD 中,优先使用系统级 Secret,而非本地加密。
11.5 企业级 Maven 使用规范
| 规范领域 | 推荐实践 | 说明 |
|---|---|---|
| 目录结构 | 遵循标准 Maven 结构 | src/main/java, src/test/java, src/main/resources 等,确保工具兼容性。 |
| POM 管理 | 统一使用企业 Parent POM 或 BOM / 禁止在 pom.xml 中使用 LATEST/RELEASE / 所有依赖通过 dependencyManagement 管理 | 实现技术栈统一和版本可控。 |
| 版本管理 | 使用语义化版本(SemVer)/ SNAPSHOT 用于开发,Release 用于生产 / 发布使用 maven-release-plugin | 确保版本清晰可追溯。 |
| 仓库策略 | 所有项目使用企业 Nexus/Artifactory 作为镜像 / 禁止直接访问中央仓库 / 私有构件必须部署到私服 | 集中管理,保障安全和效率。 |
| 构建流程 | CI/CD 流水线标准化(构建 → 测试 → 扫描 → 部署)/ 发布流程自动化 / 构建日志归档 | 提高交付质量和可审计性。 |
| 安全性 | settings.xml 模板分发,密码加密 / 集成安全扫描(OWASP)/ 定期审查依赖 | 防范供应链攻击。 |
| 文档与培训 | 提供内部 Maven 指南 / 新员工培训 | 降低使用门槛,保证规范落地。 |
| 工具链统一 | 规定 Maven 版本(如 3.8.6)/ 统一 IDE 导入配置 | 避免因环境差异导致问题。 |
| 多模块项目 | 推荐聚合与继承合一模式 / 明确模块职责(common, service, web)/ 避免循环依赖 | 保证项目结构清晰。 |
| 性能监控 | 监控构建时长 / 分析慢构建原因 | 持续优化开发体验。 |
企业级 settings.xml 模板示例:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
<localRepository>/opt/maven/repo</localRepository>
<mirrors>
<mirror>
<id>company-nexus</id>
<mirrorOf>*</mirrorOf>
<url>https://nexus.company.com/repository/maven-all/</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>company</id>
<activation><activeByDefault>true</activeByDefault></activation>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</profile>
</profiles>
<!-- 加密的服务器配置 -->
<servers>
<server>
<id>nexus-releases</id>
<username>${env.DEPLOY_USER}</username>
<password>${env.DEPLOY_PASS}</password>
</server>
</servers>
</settings>
(在 CI/CD 中通过环境变量注入凭证)
第十二章:Maven 与 IDE 集成
12.1 IntelliJ IDEA 中使用 Maven
| 功能 | 操作方式 | 说明 |
|---|---|---|
| 项目导入 | File → Open → 选择 pom.xml 文件 | IDEA 会自动识别为 Maven 项目并导入。 |
| Maven 工具窗口 | 右侧边栏 Maven 标签页 | 核心操作入口,展示项目模块、生命周期、插件、依赖。 |
| 执行生命周期 | 在 Maven 窗口中双击 compile, test, package, install 等 | 图形化执行 Maven 命令,无需记忆命令行。 |
| 执行自定义命令 | Maven 窗口 → 点击 Execute Maven Goal (小闪电图标) → 输入命令(如 clean compile -Pprod) | 执行复杂或带参数的命令。 |
| 刷新项目 | Maven 窗口 → 点击 Reload All Maven Projects (刷新图标) | 当 pom.xml 被手动修改后,同步配置到 IDE。 |
| 依赖管理 | pom.xml 中编辑 <dependencies> → Reload | 添加/删除依赖后,IDE 会自动下载并加入类路径。 |
| 多模块项目 | 自动识别 modules,在项目视图中分层显示 | 可在 Maven 窗口中选择作用于单个模块或整个项目。 |
| 运行/调试 | 右键 main 方法或测试类 → Run / Debug | 使用 Maven 管理的依赖和类路径。 |
| 插件集成 | 如 spring-boot-maven-plugin → Maven 窗口会显示 spring-boot:run 目标 | 可直接点击运行 Spring Boot 应用。 |
| 设置 | Settings → Build, Execution, Deployment → Build Tools → Maven | 配置 Maven home, settings.xml, 本地仓库路径。 |
最佳实践:
- 保持 Maven home 与命令行
mvn -v版本一致。 - 使用 Reload 确保 IDE 配置与
pom.xml同步。 - 利用 Maven 窗口的 Dependencies 标签可视化依赖树。
12.2 Eclipse(M2Eclipse)中使用 Maven
| 功能 | 操作方式 | 说明 |
|---|---|---|
| 项目导入 | File → Import → Maven → Existing Maven Projects → 选择项目根目录 | Eclipse 的标准 Maven 导入方式。 |
| Maven 工具窗口 | 底部或侧边 Maven 视图(需安装 M2E 插件) | 显示项目、生命周期、插件等。 |
| 执行生命周期 | 右键项目 → Run As → Maven build… → 在 Goals 输入 compile, install 等 | 或使用预设的 Run As 快捷选项(如 Maven clean, Maven install)。 |
| 配置构建 | Run As → Maven build… → 可设置 User settings, Profiles, Goals 等 | 创建可复用的运行配置。 |
| 更新项目 | 右键项目 → Maven → Update Project… (快捷键 Alt+F5) | 关键操作:当 pom.xml 变更后,必须执行此操作同步依赖和配置。 |
| 依赖管理 | 编辑 pom.xml → Update Project | 依赖会自动下载并添加到 Maven Dependencies 类路径容器。 |
| 插件错误 | 常见错误:Plugin execution not covered by lifecycle configuration | 解决方案:1. Update Project / 2. 安装对应的 m2e 连接器(m2e-connectors) / 3. 在 pom.xml 中添加 <pluginManagement> 忽略配置 |
| 多模块项目 | 自动识别聚合结构,在 Package Explorer 中以项目形式展示 | 可对父项目或子模块单独执行 Maven 命令。 |
| 运行/调试 | 右键 main 类 → Run As → Java Application | 使用 Maven 解析的依赖。 |
最佳实践:
- 频繁使用 Alt+F5 (Update Project) 保持同步。
- 遇到插件问题,优先检查是否需要安装 m2e 连接器。
- 确保
settings.xml配置正确(在 Preferences → Maven → User Settings 中设置)。
12.3 VS Code 中使用 Maven
| 功能 | 扩展/操作方式 | 说明 |
|---|---|---|
| 核心扩展 | 安装 Maven for Java (由 Microsoft 提供) | 提供 Maven 项目支持。 |
| 项目识别 | 打开包含 pom.xml 的文件夹 | 扩展会自动激活并扫描 Maven 项目。 |
| Maven 视图 | 左侧活动栏 Maven 图标 | 展示项目结构、生命周期、依赖、插件。 |
| 执行命令 | 在 Maven 视图中点击生命周期目标(如 compile, package) | 图形化执行,结果在 OUTPUT 或 TERMINAL 标签页显示。 |
| 自定义命令 | Maven 视图 → 点击 Execute Maven Goal → 输入命令 | 执行复杂命令。 |
| 依赖管理 | 编辑 pom.xml 文件 | 保存后,扩展会提示 Import changes?,点击确认即可下载依赖。 |
| 运行/调试 | 需配合 Extension Pack for Java | 安装后,可右键 main 方法 → Run / Debug。 |
| 设置 | settings.json (Ctrl+, → 打开设置) | 配置 "maven.executable.path" 指向 mvn 可执行文件。 |
| 终端集成 | 内置终端 (`Ctrl+“) | 可直接运行 mvn 命令,与图形界面互补。 |
最佳实践:
- 确保系统 PATH 中有
mvn,或在设置中明确指定路径。 - 依赖更改后,留意弹出的 Import changes? 提示。
- VS Code 的 Maven 功能相对轻量,复杂项目建议使用 IDEA 或 Eclipse。
12.4 IDE 与命令行构建一致性
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 依赖不同 | IDE 使用的 settings.xml 或本地仓库路径与命令行不同。 | 1. 在 IDE 设置中指定与命令行相同的 settings.xml 和 MAVEN_HOME。2. 确认 localRepository 配置一致。 |
| JDK 版本不同 | IDE 内置 JDK 与 MAVEN_OPTS 或系统 JAVA_HOME 不同。 | 1. 在 IDE 中配置项目 SDK 为与 maven-compiler-plugin 一致的版本。2. 检查 JAVA_HOME 环境变量。 |
| 构建结果不同 | IDE 增量编译,命令行 clean 后全量编译。 | 1. IDE 构建前执行 clean 操作。2. 命令行构建使用 mvn compile 进行增量对比。 |
| 插件行为差异 | IDE 未完全支持某些 Maven 插件的生命周期绑定。 | 1. 优先以命令行构建结果为准(CI/CD 的标准)。 2. 在 IDE 中通过 Run Configuration 执行完整的 mvn clean package 命令。 |
| Profile 未激活 | IDE 默认未激活某些 Profile。 | 1. 在 IDE 的 Maven 设置中手动激活所需 Profile(如 IDEA 的 Maven → Profiles)。 2. 在 pom.xml 中设置 <activeByDefault>true</activeByDefault>。 |
| 资源过滤未生效 | IDE 未触发资源复制和过滤。 | 1. 在 IDE 中执行 Maven → Generate Resources 或 Process Resources。 2. 执行完整的 package 生命周期。 |
确保一致性的最佳实践:
- 统一工具链: 团队内约定 Maven 版本、JDK 版本,并在文档中明确。
- 使用
settings.xml模板: 分发统一的settings.xml,配置镜像仓库和服务器。 - CI/CD 为黄金标准: 将 CI/CD 流水线(如 Jenkins, GitHub Actions)的构建结果视为最终标准。
- 定期验证: 在本地执行
mvn clean package,并与 IDE 构建产物(如target/下的 JAR)对比。 - 文档化: 在项目 README 中写明推荐的 IDE 配置和构建命令。
终极检查:
# 在项目根目录执行
mvn clean package
# 检查 target/ 目录下的构件是否符合预期
任何 IDE 配置都应以能成功执行此命令并产生正确结果为最终目标。