1. Maven 核心理念
Maven 不仅仅是一个构建工具,它还是一个项目管理工具。它通过 pom.xml (Project Object Model) 来管理项目的依赖、构建流程和文档。
2. 常用命令与场景
2.1 基础构建命令
| 命令 | 适用场景 | 详细说明 |
|---|---|---|
mvn clean | 开始新构建前 | 清理 target 目录,防止旧编译文件干扰。 |
mvn compile | 验证代码 | 仅编译源代码,快速检查语法错误。 |
mvn test | 单元测试 | 运行 src/test/java 下的测试用例。 |
mvn package | 本地测试运行 | 将项目打包(Jar/War),存放在 target 下。 |
mvn install | 本地多模块开发 | 将包安装到本地仓库 (~/.m2/repository),供本地其他项目引用。 |
mvn deploy | 团队协作发布 | 将包推送到公司私服 (Nexus),供团队其他成员下载。 |
2.2 进阶诊断命令
- 查看依赖冲突:
mvn dependency:tree- 场景: 当出现
NoSuchMethodError时,查看是哪个 Jar 包引入了错误版本。
- 场景: 当出现
- 分析依赖:
mvn dependency:analyze- 场景: 检查项目中是否有未使用的依赖,或隐式引用的依赖。
- 跳过测试构建:
mvn clean install -DskipTests- 场景: 紧急打包且确定测试已通过时使用。
2.3 万能救急与实用命令
- 彻底重下依赖:
mvn dependency:purge-local-repository -DmanualInclude="*" -DreResolve=true- 场景: 遇到依赖包损坏、Jar 包拉取不全或本地仓库索引混乱导致的莫名编译失败。此命令会清理本地仓库中当前项目相关的依赖并强制重新下载。
- 强制更新快照:
mvn clean install -U- 场景: 团队开发中,同事更新了 Snapshot 版本代码并推送到私服,但你本地没有同步更新。
-U会强制检查远程仓库。
- 场景: 团队开发中,同事更新了 Snapshot 版本代码并推送到私服,但你本地没有同步更新。
- 查看最终 POM:
mvn help:effective-pom- 场景: 多层继承或配置了大量 Profile 后,不确定最终配置是什么。此命令会输出所有配置叠加后的完整 POM。
- 批量修改版本号:
mvn versions:set -DnewVersion=2.0.0- 场景: 多模块项目需要统一升级版本号时,避免手动修改几十个
pom.xml。
- 场景: 多模块项目需要统一升级版本号时,避免手动修改几十个
- 下载源码与文档:
mvn dependency:sources -DdownloadJavadocs=true- 场景: 刚拉取项目,需要阅读依赖库源码或查看 Javadoc 文档时使用。
- 查看激活的 Profile:
mvn help:active-profiles- 场景: 确定当前构建环境到底命中了哪个 Profile 配置。
3. POM 核心标签深度解析
3.1 资源打包配置 (<resources>)
这是最容易出错的配置项。默认情况下,Maven 只会打包 src/main/resources 下的文件。
<build>
<resources>
<resource>
<!-- 指定资源文件所在目录 -->
<directory>src/main/resources</directory>
<!-- 开启变量过滤: 允许使用 @property@ 引用 pom 或 profile 中的变量 -->
<filtering>true</filtering>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/*.yml</exclude>
</excludes>
</resource>
</resources>
</build>
如果不加或配置错误的后果:
- 资源丢失: 如果你的 XML 映射文件(如 MyBatis 的 Mapper)放在
src/main/java下,默认构建会忽略它们,导致运行时报BindingException。 - 变量未替换: 如果不开启
<filtering>true</filtering>,配置文件中的@env@或${db.url}不会被替换,导致程序连接到错误的环境。 - 二进制损坏: 如果对图片、Excel 等二进制文件开启了
filtering,Maven 的文本替换尝试会破坏这些文件的二进制结构,导致文件损坏。
3.2 依赖管理与冲突控制
<dependencyManagement> vs <dependencies>
<dependencies>: 只要配置了,子模块就会强制继承。<dependencyManagement>: 只是声明版本。子模块只有显式引用该依赖(且不写版本号)时,才会生效。- 不使用的后果: 各模块依赖版本不一,导致线上出现难以排查的“由于依赖版本冲突导致的类找不到”问题。
<optional> 标签
- 作用: 标记该依赖不会被传递给下游项目。
- 场景: 开发一个 SDK,支持多种数据库(MySQL/Oracle)。你可以将驱动设为
optional,让 SDK 的使用者自己决定引入哪个驱动。 - 不使用的后果: 你的 SDK 使用者会强制拉取一大堆他们根本不需要的 Jar 包,导致包体臃肿。
3.3 构建生命周期插件 (<plugins>)
spring-boot-maven-plugin
- 作用: 将普通的 Jar 包重新打包成“胖 Jar”(Fat Jar),包含所有依赖和内置容器。
- 不使用的后果: 打出的 Jar 包只有你写的几 KB 代码,无法直接通过
java -jar运行,因为缺少 Spring 框架和三方库。
3.4 环境隔离 (<profiles>)
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault> <!-- 默认激活 -->
</activation>
<properties>
<db.url>jdbc:mysql://localhost:3306/dev</db.url>
</properties>
</profile>
</profiles>
实战价值: 配合 3.1 节的 <filtering>,可以实现“一次配置,全环境通用”。不加这个标签,你可能需要手动在打包前修改 application.yml,极其容易在生产环境配置测试数据库,造成重大事故。
4. 常见实战场景
4.1 解决依赖冲突
问题: 两个依赖分别引入了 log4j 的 1.2 和 2.0 版本。
方案:
- 使用
mvn dependency:tree找到路径。 - 在
pom.xml中使用<exclusions>排除低版本。 - 或者直接在当前项目
<dependencies>中显式声明高版本(Maven 优先使用路径最短的)。
4.2 多环境打包
命令: mvn clean package -Pprod
原理: 配合 <profiles> 和 filtering,在打包时自动替换资源文件(如 application.yml)中的变量。
4.3 模块化开发
结构: 父工程 pom (packaging 为 pom) 管理子模块。
优势: 一次 mvn install 即可构建整个项目链,确保内部依赖始终最新。
4.4 离线模式
命令: mvn clean install -o
场景: 在没有网络的情况下,只使用本地仓库已有的 Jar 包进行构建。