本文聚焦 Java 工程化的「基础设施」------ Maven。从 P1 阶段走来,你已经掌握了 Java 语言核心、JVM 原理、并发编程,写的代码能跑、能调、能排查。但一旦进入团队协作、依赖管理、多服务开发,靠「手写 javac」和「拖 jar 包」就完全不够用了。Maven 是 Java 世界最主流的构建工具,几乎所有企业项目都在用。本文会从最基础的「坐标」概念讲起,让你理解为什么一个 GAV 能唯一确定一个构件;然后深入 Maven 的三大生命周期,搞清楚 compile、test、package、install、deploy 这些命令到底做了什么;最后介绍多模块项目的结构设计,帮助你理解为什么企业级项目要拆成 parent、common、api、service 多个子工程。读完本文,你将掌握 Maven 的核心概念和最佳实践,为后续 Spring Boot、微服务、CI/CD 打下坚实的工程基础。
如果你之前只是「复制粘贴 pom.xml」,运行 mvn clean install 时只知道盯着 BUILD SUCCESS 或 FAILURE,那这篇会帮你把「黑盒」打开。下面我按坐标与仓库 → 生命周期与插件 → 多模块结构 → 实战踩坑的顺序往下聊。
1. Maven 是什么:从「手工构建」到「标准化工程」
1.1 没有 Maven 的日子
假设你要开发一个 Java Web 项目,没有构建工具时,流程是这样的:
- 手动下载 jar 包(Spring、MyBatis、Jackson......)
- 放到项目的
lib/目录 - 手动配置 IDE 的 classpath
- 运行
javac编译,java运行 - 打包时手动复制依赖 jar,写 MANIFEST.MF
这会带来一系列问题:
- 版本冲突:项目 A 用 Spring 5.3,项目 B 用 Spring 6.0,jar 包混用导致诡异异常
- 依赖传递:你引入 spring-web,但它依赖 spring-core、spring-beans......手动管理极其痛苦
- 构建不一致:开发环境和生产环境的依赖版本可能不同
- 协作困难:新人入职要花半天配环境
1.2 Maven 解决了什么
Maven 的核心价值是「标准化 + 自动化」:
- 标准化:统一的项目结构、构建流程、依赖管理方式
- 自动化:一键编译、测试、打包、发布
- 依赖管理:自动下载依赖、解决传递依赖、排除冲突
Maven 的核心理念是「约定优于配置(Convention over Configuration)」:
${project.basedir}/
├── pom.xml # 项目配置文件
├── src/
│ ├── main/
│ │ ├── java/ # 源代码
│ │ ├── resources/ # 资源文件
│ │ └── webapp/ # Web 应用(WAR 项目)
│ └── test/
│ ├── java/ # 测试代码
│ └── resources/ # 测试资源
└── target/ # 构建输出
这个目录结构是 Maven 约定的,不需要你手动配置。只要遵循约定,Maven 就知道去哪里找源代码、测试代码、资源文件。
1.3 Maven 与 Gradle 的关系
Gradle 是另一个主流构建工具,采用 Groovy/Kotlin DSL,灵活性更高:
| 特性 | Maven | Gradle |
|---|---|---|
| 配置语言 | XML(声明式) | Groovy/Kotlin DSL(编程式) |
| 构建速度 | 较慢(每次重新解析) | 快(增量构建、构建缓存) |
| 学习曲线 | 低 | 中 |
| 生态成熟度 | 极高 | 高 |
| 企业应用 | 传统企业、Spring 官方支持 | Android、新项目 |
本文聚焦 Maven,Gradle 会在 035 篇专门讲解。
2. 坐标系统:GAV 的含义与仓库机制
2.1 什么是 GAV 坐标
Maven 使用「坐标」唯一标识一个构件(Artifact)。坐标由三部分组成:G roupId、A rtifactId、V ersion,简称 GAV。
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.3.4</version>
</dependency>
groupId:组织或公司的反向域名
- 通常是域名反转:
com.alibaba、org.springframework - 区分不同组织的项目
artifactId:项目或模块名称
- 具体的构件名称:
fastjson、spring-boot-starter-web - 一个组织可以有多个 artifactId
version:版本号
- 正式版:
3.3.4 - 快照版:
3.3.4-SNAPSHOT(开发中的版本) - 里程碑版:
3.3.0-M1、3.3.0-RC1
2.2 坐标与仓库路径的映射
Maven 根据坐标自动计算构件在仓库中的路径:
groupId: org.springframework.boot
artifactId: spring-boot-starter-web
version: 3.3.4
packaging: jar
↓ 映射到仓库路径
${repository}/org/springframework/boot/spring-boot-starter-web/3.3.4/spring-boot-starter-web-3.3.4.jar
规律 :groupId 按 . 分隔成目录层级,artifactId 和 version 组成最终文件名。
2.3 仓库类型:本地、中央、私服
Maven 有三种仓库类型:
本地仓库(Local Repository)
- 位置:
~/.m2/repository(默认) - 作用:缓存已下载的构件,避免重复下载
- 配置:
~/.m2/settings.xml
xml
<settings>
<localRepository>/path/to/local/repo</localRepository>
</settings>
中央仓库(Central Repository)
- 位置:https://repo.maven.apache.org/maven2
- 作用:Maven 官方维护的公共仓库
- 特点:包含绝大多数开源构件
私服(Private Repository)
- 常见产品:Nexus、Artifactory
- 作用:企业内部构件的发布和代理
- 优势:
- 加速下载(代理中央仓库)
- 统一管理(内部构件、第三方构件)
- 权限控制
仓库查找顺序:
- 本地仓库 → 有则使用
- 私服(如配置)→ 有则下载到本地
- 中央仓库 → 下载到本地
2.4 settings.xml 配置详解
settings.xml 是 Maven 的全局配置文件,位于 ~/.m2/settings.xml。
配置私服镜像:
xml
<settings>
<mirrors>
<mirror>
<id>aliyun</id>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>
配置私服认证:
xml
<settings>
<servers>
<server>
<id>company-releases</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>
</settings>
配置 profile:
xml
<settings>
<profiles>
<profile>
<id>dev</id>
<properties>
<env>dev</env>
</properties>
<repositories>
<repository>
<id>company-snapshots</id>
<url>https://nexus.company.com/repository/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>dev</activeProfile>
</activeProfiles>
</settings>
3. 生命周期:Maven 的「骨架」
3.1 三大生命周期
Maven 定义了三套相互独立的生命周期(Lifecycle):
| 生命周期 | 作用 | 关键阶段 |
|---|---|---|
| clean | 清理项目 | pre-clean → clean → post-clean |
| default | 构建核心 | validate → compile → test → package → install → deploy |
| site | 生成文档 | pre-site → site → post-site → site-deploy |
重要规则:
- 执行某个阶段时,之前的阶段会自动执行
- 例如执行
mvn package,会依次执行 validate → compile → test → package - 三套生命周期相互独立,执行
mvn clean package会触发 clean 和 default 两套
3.2 default 生命周期详解
default 生命周期是最常用的,包含以下阶段(按顺序):
validate → 验证项目结构
initialize → 初始化构建状态
generate-sources → 生成源代码
process-sources → 处理源代码
generate-resources → 生成资源
process-resources → 处理资源(复制到 target)
compile → 编译源代码
process-classes → 处理编译后的类
generate-test-sources → 生成测试源代码
process-test-sources → 处理测试源代码
generate-test-resources → 生成测试资源
process-test-resources → 处理测试资源
test-compile → 编译测试代码
process-test-classes → 处理测试类
test → 运行单元测试
prepare-package → 准备打包
package → 打包(jar/war)
pre-integration-test → 集成测试准备
integration-test → 运行集成测试
post-integration-test → 集成测试收尾
verify → 验证打包结果
install → 安装到本地仓库
deploy → 部署到远程仓库
常用命令:
bash
# 编译
mvn compile
# 编译 + 测试
mvn test
# 编译 + 测试 + 打包
mvn package
# 编译 + 测试 + 打包 + 安装到本地仓库
mvn install
# 编译 + 测试 + 打包 + 部署到远程仓库
mvn deploy
# 清理 + 打包
mvn clean package
# 跳过测试
mvn package -DskipTests
# 跳过测试编译和执行
mvn package -Dmaven.test.skip=true
3.3 clean 生命周期
pre-clean → 清理前的工作
clean → 删除 target 目录
post-clean → 清理后的工作
常用命令:
bash
# 清理 target 目录
mvn clean
# 清理 + 打包
mvn clean package
3.4 site 生命周期
pre-site → 生成文档前的准备
site → 生成项目文档网站
post-site → 文档生成后的工作
site-deploy → 发布文档到服务器
常用命令:
bash
# 生成文档
mvn site
# 生成文档并发布
mvn site-deploy
3.5 插件与目标
Maven 的核心只是一个骨架,具体的构建工作由插件(Plugin)完成。每个插件包含多个目标(Goal)。
常见插件:
| 插件 | 作用 | 常用目标 |
|---|---|---|
| maven-compiler-plugin | 编译 Java 代码 | compile、testCompile |
| maven-surefire-plugin | 运行单元测试 | test |
| maven-jar-plugin | 打包 JAR | jar |
| maven-war-plugin | 打包 WAR | war |
| maven-install-plugin | 安装到本地仓库 | install |
| maven-deploy-plugin | 部署到远程仓库 | deploy |
| maven-clean-plugin | 清理构建 | clean |
| maven-resources-plugin | 处理资源文件 | resources、testResources |
插件绑定关系:
- Maven 在生命周期的每个阶段,默认绑定了某些插件目标
- 例如
compile阶段绑定了maven-compiler-plugin:compile - 你可以自定义绑定
查看插件绑定:
bash
mvn help:describe -Dcmd=compile -Ddetail
4. pom.xml 核心配置
4.1 基本结构
xml
<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
<artifactId>demo-project</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!-- 基本信息 -->
<name>Demo Project</name>
<description>A demo Maven project</description>
<!-- 属性 -->
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>3.3.4</spring-boot.version>
</properties>
<!-- 依赖 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
<!-- 构建 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</build>
</project>
4.2 依赖范围(Scope)
依赖范围决定了依赖在什么阶段可用:
| Scope | 编译 | 测试 | 运行 | 打包 | 示例 |
|---|---|---|---|---|---|
| compile(默认) | ✓ | ✓ | ✓ | ✓ | spring-core |
| provided | ✓ | ✓ | ✗ | ✗ | servlet-api、lombok |
| runtime | ✗ | ✓ | ✓ | ✓ | mysql-connector-java |
| test | ✗ | ✓ | ✗ | ✗ | junit、mockito |
| system | ✓ | ✓ | ✗ | ✗ | 本地 jar(不推荐) |
| import | - | - | - | - | dependencyManagement(仅 pom) |
示例:
xml
<dependencies>
<!-- compile 范围(默认) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- provided 范围:编译时需要,运行时由容器提供 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- runtime 范围:运行时才需要 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- test 范围:仅测试时使用 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
4.3 依赖传递与排除
依赖传递:
当 A 依赖 B,B 依赖 C 时,A 会自动获得对 C 的依赖。
A → B → C
但以下情况不会传递:
- C 的 scope 是
provided或test - B 对 C 设置了
<optional>true</optional> - A 对 B 设置了
<exclusions>
依赖排除:
xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.43</version>
<exclusions>
<!-- 排除传递依赖 -->
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-framework</artifactId>
</exclusion>
</exclusions>
</dependency>
可选依赖:
xml
<dependency>
<groupId>org.example</groupId>
<artifactId>some-lib</artifactId>
<version>1.0.0</version>
<optional>true</optional> <!-- 不会传递给下游 -->
</dependency>
4.4 查看依赖树
bash
# 查看依赖树
mvn dependency:tree
# 查看特定依赖的来源
mvn dependency:tree -Dincludes=org.springframework:spring-core
# 分析依赖冲突
mvn dependency:analyze
依赖树示例:
com.example:demo-project:jar:1.0.0-SNAPSHOT
+- org.springframework.boot:spring-boot-starter-web:jar:3.3.4:compile
| +- org.springframework.boot:spring-boot-starter:jar:3.3.4:compile
| | +- org.springframework.boot:spring-boot:jar:3.3.4:compile
| | +- org.springframework.boot:spring-boot-autoconfigure:jar:3.3.4:compile
| | \- org.springframework.boot:spring-boot-starter-logging:jar:3.3.4:compile
| +- org.springframework.boot:spring-boot-starter-json:jar:3.3.4:compile
| +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.3.4:compile
| \- org.springframework:spring-webmvc:jar:6.1.14:compile
\- org.projectlombok:lombok:jar:1.18.30:provided
5. 多模块项目:企业级项目的标准结构
5.1 为什么需要多模块
单模块项目在规模较小时没问题,但随着项目增长,会面临:
- 代码耦合:所有代码在一个模块,边界不清晰
- 复用困难:公共服务无法被其他项目复用
- 构建缓慢:修改一行代码,整个项目都要重新构建
- 团队协作:多人同时修改一个模块,冲突频繁
多模块项目的优势:
- 职责分离:每个模块有明确的职责
- 依赖管理:统一管理版本,避免冲突
- 按需构建:只构建修改的模块
- 复用性:公共模块可以被多个项目使用
5.2 多模块项目结构
典型结构:
demo-parent/ # 父工程
├── pom.xml # 父 pom
├── demo-common/ # 公共模块
│ ├── pom.xml
│ └── src/
├── demo-api/ # API 模块(对外接口)
│ ├── pom.xml
│ └── src/
├── demo-service/ # 业务服务模块
│ ├── pom.xml
│ └── src/
└── demo-web/ # Web 模块(启动入口)
├── pom.xml
└── src/
5.3 父 pom 配置
父 pom 的职责:
- 定义公共属性(版本号、编码等)
- 管理依赖版本(dependencyManagement)
- 管理插件版本(pluginManagement)
- 声明子模块
xml
<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
<artifactId>demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging> <!-- 父工程必须是 pom 类型 -->
<name>Demo Parent</name>
<description>多模块项目父工程</description>
<!-- 子模块 -->
<modules>
<module>demo-common</module>
<module>demo-api</module>
<module>demo-service</module>
<module>demo-web</module>
</modules>
<!-- 公共属性 -->
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>3.3.4</spring-boot.version>
<mybatis-plus.version>3.5.9</mybatis-plus.version>
<hutool.version>5.8.32</hutool.version>
</properties>
<!-- 依赖管理:只声明版本,不实际引入 -->
<dependencyManagement>
<dependencies>
<!-- Spring Boot BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 内部模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-service</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 第三方依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 公共依赖:所有子模块都会继承 -->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- 插件管理 -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
5.4 子模块 pom 配置
demo-common(公共模块):
xml
<?xml version="1.0" encoding="UTF-8"?>
<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>
<!-- 继承父 pom -->
<parent>
<groupId>com.example</groupId>
<artifactId>demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>demo-common</artifactId>
<packaging>jar</packaging>
<name>Demo Common</name>
<description>公共工具类、常量、基础配置</description>
<dependencies>
<!-- 这里不需要写 version,由父 pom 统一管理 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
</dependencies>
</project>
demo-api(API 模块):
xml
<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
<artifactId>demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>demo-api</artifactId>
<packaging>jar</packaging>
<name>Demo API</name>
<description>对外暴露的接口定义、DTO、VO</description>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
</project>
demo-service(业务模块):
xml
<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
<artifactId>demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>demo-service</artifactId>
<packaging>jar</packaging>
<name>Demo Service</name>
<description>业务逻辑、数据访问层</description>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
</dependencies>
</project>
demo-web(启动模块):
xml
<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
<artifactId>demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>demo-web</artifactId>
<packaging>jar</packaging>
<name>Demo Web</name>
<description>Web 层、启动入口</description>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-service</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 打包为可执行 jar -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
5.5 多模块构建命令
bash
# 在父工程目录执行,构建所有模块
mvn clean install
# 只构建指定模块(同时构建依赖的模块)
mvn clean install -pl demo-web -am
# 参数说明:
# -pl (--projects) 指定要构建的模块
# -am (--also-make) 同时构建依赖的模块
# -amd (--also-make-dependents) 同时构建依赖于该模块的模块
# 跳过指定模块
mvn clean install -pl !demo-web
# 只编译,不运行测试
mvn clean install -DskipTests
# 指定线程数并行构建
mvn clean install -T 4
# 离线模式(使用本地仓库)
mvn clean install -o
6. 常见问题与最佳实践
6.1 依赖冲突排查
问题现象:
java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationUtils.getDeclaredAnnotations(Ljava/lang/Class;)[Ljava/lang/annotation/Annotation;
这类错误通常是依赖版本冲突导致的:编译时用的是 A 版本,运行时加载的是 B 版本。
排查步骤:
bash
# 1. 查看依赖树
mvn dependency:tree
# 2. 查找特定依赖的来源
mvn dependency:tree -Dincludes=org.springframework:spring-core
# 3. 分析依赖问题
mvn dependency:analyze
解决方法:
- 使用
dependencyManagement统一版本 - 使用
<exclusions>排除冲突依赖 - 使用
mvn dependency:analyze检查未使用的依赖
6.2 版本号管理最佳实践
使用属性统一管理版本:
xml
<properties>
<spring-boot.version>3.3.4</spring-boot.version>
<mybatis-plus.version>3.5.9</mybatis-plus.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
使用 BOM(Bill of Materials):
Spring Boot、Spring Cloud 都提供了 BOM,可以简化版本管理:
xml
<dependencyManagement>
<dependencies>
<!-- Spring Boot BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.3.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud BOM -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2023.0.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
版本号命名规范:
- 正式版本:
1.0.0、2.1.3 - 快照版本:
1.0.0-SNAPSHOT(开发中,每次构建会检查更新) - 里程碑版本:
1.0.0-M1、1.0.0-RC1(预发布) - 发布候选版本:
1.0.0-RELEASE(不推荐,正式版直接用1.0.0)
6.3 多模块分层原则
常见分层结构:
demo-parent/
├── demo-common/ # 最底层,无业务依赖
│ └── 工具类、常量、枚举、基础配置
├── demo-api/ # 接口层,依赖 common
│ └── DTO、VO、接口定义
├── demo-domain/ # 领域层,依赖 api(可选)
│ └── 实体、领域服务
├── demo-repository/ # 数据访问层,依赖 domain(可选)
│ └── Mapper、Repository
├── demo-service/ # 业务逻辑层,依赖 repository
│ └── Service、业务逻辑
└── demo-web/ # Web 层,依赖 service
└── Controller、启动类
依赖方向原则:
- 单向依赖:上层依赖下层,下层不能依赖上层
- 避免循环依赖:A → B → A 是绝对禁止的
- 公共下沉:公共代码放到 common 模块
6.4 Maven 常用命令速查
bash
# 清理
mvn clean
# 编译
mvn compile
# 打包
mvn package
# 安装到本地仓库
mvn install
# 部署到远程仓库
mvn deploy
# 运行测试
mvn test
# 跳过测试
mvn package -DskipTests
# 查看依赖树
mvn dependency:tree
# 分析依赖
mvn dependency:analyze
# 查看有效 pom
mvn help:effective-pom
# 查看插件帮助
mvn help:describe -Dplugin=compiler -Ddetail
# 创建项目(archetype)
mvn archetype:generate -DgroupId=com.example -DartifactId=demo -DarchetypeArtifactId=maven-archetype-quickstart
# 创建 Web 项目
mvn archetype:generate -DgroupId=com.example -DartifactId=demo-web -DarchetypeArtifactId=maven-archetype-webapp
7. 综合示例:从零搭建多模块项目
7.1 创建父工程
bash
# 创建父工程目录
mkdir demo-parent && cd demo-parent
# 创建父 pom.xml
父 pom 内容见上文 5.3 节。
7.2 创建子模块
bash
# 创建子模块目录
mkdir -p demo-common/src/main/java/com/example/common
mkdir -p demo-common/src/main/resources
mkdir -p demo-api/src/main/java/com/example/api
mkdir -p demo-service/src/main/java/com/example/service
mkdir -p demo-web/src/main/java/com/example/web
mkdir -p demo-web/src/main/resources
7.3 构建与运行
bash
# 在父工程目录执行
mvn clean install
# 启动 Spring Boot(在 demo-web 目录)
cd demo-web
mvn spring-boot:run
7.4 常见问题
问题一:父 pom 找不到子模块
确保子模块目录名与 <module> 标签中的名称一致,且子模块目录下有 pom.xml 文件。
问题二:依赖版本冲突
使用 mvn dependency:tree 查看依赖树,在父 pom 的 dependencyManagement 中统一版本。
问题三:循环依赖
确保依赖方向正确:common → api → service → web。使用 mvn dependency:tree 检查是否有循环依赖。
问题四:SNAPSHOT 版本不更新
bash
# 强制更新 SNAPSHOT
mvn clean install -U
小结
- GAV 坐标是 Maven 构件的唯一标识,由 groupId、artifactId、version 三部分组成,映射到仓库路径
- 三大生命周期(clean、default、site)相互独立,执行某个阶段会自动执行之前的所有阶段
- 依赖范围(compile、provided、runtime、test)决定了依赖在不同阶段的可见性
- dependencyManagement 用于统一管理版本,子模块引用时不需要写版本号
- 多模块项目通过父 pom 继承和聚合,实现职责分离、统一版本、按需构建
- 排查依赖冲突的核心命令是
mvn dependency:tree和mvn dependency:analyze
P2 阶段开篇说明:
从本篇开始,我们进入 P2 工程化与协作阶段。Maven 是这个阶段的基础,后续的 Spring Boot 项目搭建、单元测试、CI/CD 都会用到 Maven 的知识。下一篇我们将深入依赖管理的「深水区」------依赖冲突与排除、dependencyManagement 的最佳实践,帮助你从容应对企业级项目中的依赖地狱问题。
下一篇(034)预告:依赖冲突与排除;dependencyManagement。