全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-23 12 分钟 ✍️ juanwangdev

Maven 核心概念

理解 Maven 的五大核心概念是掌握 Maven 的关键。这五个概念不是孤立的,而是相互关联形成一个完整的构建体系。本文将详细解释每个概念及其关系,帮助你建立完整的 Maven 知识框架。

为什么需要理解核心概念

只会用命令不够

很多开发者只知道 mvn clean install,但遇到问题时不知所措:

Bash
场景:依赖版本冲突报错
不懂概念:只知道报错,不知道 dependency:tree 能诊断
理解概念:知道依赖传递机制,知道如何用 exclusions 解决

场景:多模块项目构建顺序问题
不懂概念:随意放 modules,构建失败
理解概念:知道反应堆机制,知道依赖方向决定构建顺序

场景:环境配置切换
不懂概念:手动修改配置文件
理解概念:知道 Profile 概念,知道 -Pdev 切换环境

结论:理解核心概念才能高效使用 Maven,遇到问题能快速定位解决。

五大核心概念关系图

XML
              ┌──────────────────┐
              │      POM         │
              │  项目对象模型      │
              │  (核心配置文件)    │
              └──────────┬───────┘
                         │
          ┌──────────────┼──────────────┐
          │              │              │
     ┌────▼────┐    ┌────▼────┐    ┌────▼────┐
     │  坐标   │    │  依赖   │    │  插件   │
     │定位构件 │    │引用库   │    │执行任务 │
     └────┬────┘    └────┬────┘    └────┬────┘
          │              │              │
          └──────────────┼──────────────┘
                         │
              ┌──────────▼───────────┐
              │      生命周期         │
              │     构建阶段顺序       │
              │  (compile→test→package)│
              └───────────────────────┘

理解这个关系:POM 是配置中心,坐标定位依赖和插件,依赖声明项目需要的外部库,插件执行具体构建任务,生命周期定义执行顺序。

POM(Project Object Model)

什么是 POM

POM 是 Maven 项目的核心配置文件,以 XML 格式描述项目的所有信息:

  • 项目基本信息(名称、描述、版本)
  • 项目依赖(需要哪些第三方库)
  • 构建配置(源码目录、输出目录)
  • 插件配置(如何编译、打包)
  • 环境配置(多环境 Profile)

POM 层次结构

XML
超级 POM(内置)
    ↓ 继承
父 POM(可选)
    ↓ 继承
项目 POM(pom.xml)
    ↓ 合并
有效 POM(Effective POM)

关键理解:每个项目的 pom.xml 都继承了超级 POM 的默认配置。你写的 pom.xml 是对默认配置的覆盖和补充。

超级 POM 提供了什么

超级 POM 内置了 Maven 的所有默认配置:

默认配置
源码目录src/main/java
测试目录src/test/java
输出目录target/classes
仓库地址https://repo.maven.apache.org/maven2
默认插件compiler、jar、surefire 等

这就是"约定优于配置":你不需要声明这些,Maven 已经默认配置好了。

查看 POM 配置

XML
# 查看合并后的完整配置(包含继承的配置)
mvn help:effective-pom

POM 最小结构

XML
<project>
  <modelVersion>4.0.0</modelVersion>  <!-- POM 版本,固定值 -->

  <!-- 项目坐标:唯一标识项目 -->
  <groupId>com.example</groupId>
  <artifactId>my-project</artifactId>
  <version>1.0.0</version>

  <!-- 其他配置都是可选的 -->
</project>

实际开发:一个能跑的 Maven 项目,只需要这4个元素。

坐标(Coordinates)

为什么需要坐标

问题场景:如何唯一标识全球数百万个 jar 包?

Bash
有叫 "spring" 的 jar 吗?可能有几十个
有叫 "core" 的 jar 吗?可能有几百个
版本呢?同一个项目有多个版本

如何唯一标识?
需要一个全球唯一的标识系统 → Maven 坐标

坐标三要素(GAV)

XML
groupId:artifactId:version
元素作用示例选择原则
groupId组织标识org.springframework反向域名,保证全球唯一
artifactId项目名称spring-core项目/模块名,组织内唯一
version版本号5.3.20标识同一项目的不同版本

坐标的实际用途

用途1:唯一标识构件

Bash
坐标:org.springframework:spring-core:5.3.20

全球唯一:只有 Spring 社区的 spring-core 5.3.20 版本
是这个坐标,不会和其他项目混淆

用途2:依赖声明

Bash
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.3.20</version>
</dependency>

<!-- Maven 根据坐标找到并下载这个 jar -->

用途3:仓库路径映射

Bash
坐标 → 仓库路径

org.springframework → org/springframework/
spring-core          → spring-core/
5.3.20               → 5.3.20/

完整路径:
org/springframework/spring-core/5.3.20/spring-core-5.3.20.jar

版本号的含义

text
主版本.次版本.增量版本-里程碑版本

示例:
1.0.0        → 正式版
2.0.0-alpha  → 内部测试版
2.0.0-beta   → 公开测试版
2.0.0-RC1    → 候选发布版
2.0.0        → 正式发布版
1.0.0-SNAPSHOT → 开发快照版(不稳定)

重要区别

版本类型特性使用场景
SNAPSHOT内容随时变化,每次检查更新开发期间团队内部使用
RELEASE内容固定,不会变化生产环境使用

实际建议:生产项目不要使用 SNAPSHOT 版本依赖,因为无法保证构建结果一致。

依赖(Dependency)

什么是依赖

依赖是项目需要的外部库,如 Spring、JUnit、MySQL驱动等。Maven 自动管理依赖的下载、版本和传递。

依赖声明

text
<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.20</version>
    <scope>compile</scope>   <!-- 依赖范围 -->
  </dependency>
</dependencies>

依赖范围(scope)—— 重要概念

scope 决定依赖在不同阶段的可见性

scope编译时测试时运行时打包时实际场景
compile(默认)Spring 等核心库
testJUnit 等测试库
providedServlet API(Tomcat提供)
runtimeMySQL驱动

实际应用场景

text
<!-- 场景1:核心库,全程需要 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.3.20</version>
  <scope>compile</scope>   <!-- 默认值,可省略 -->
</dependency>

<!-- 场景2:测试库,只测试时用 -->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
  <scope>test</scope>      <!-- 不打包进 jar -->
</dependency>

<!-- 场景3:容器提供的库 -->
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>  <!-- Tomcat 提供,不打包 -->
</dependency>

<!-- 场景4:运行时才需要的库 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.28</version>
  <scope>runtime</scope>   <!-- JDBC代码用接口,运行时加载驱动 -->
</dependency>

传递性依赖

概念:A 依赖 B,B 依赖 C,则 A 自动获得对 C 的依赖。

text
你的项目
    ↓ 声明依赖
spring-context
    ↓ 传递依赖
spring-core
    ↓ 传递依赖
spring-jcl(日志桥接)

你的项目自动获得:spring-context、spring-core、spring-jcl

实际好处

  • 你只需要声明直接依赖
  • 间接依赖自动引入
  • 避免遗漏依赖导致编译错误

查看传递依赖

text
mvn dependency:tree

输出:

text
[INFO] com.example:my-app:jar:1.0.0
[INFO] +- org.springframework:spring-context:jar:5.3.20
[INFO] |  +- org.springframework:spring-core:jar:5.3.20
[INFO] |  +- org.springframework:spring-jcl:jar:5.3.20

插件(Plugin)

什么是插件

插件是执行具体构建任务的工具。Maven 本身不编译代码、不打包,这些工作由插件完成:

任务执行插件
编译 Java 代码maven-compiler-plugin
执行单元测试maven-surefire-plugin
打包成 JARmaven-jar-plugin
打包成 WARmaven-war-plugin
清理 target 目录maven-clean-plugin

插件与生命周期的关系

插件目标绑定到生命周期阶段

text
生命周期阶段         绑定的插件目标

compile        →    compiler:compile(编译源码)
test           →    surefire:test(执行测试)
package        →    jar:jar(打包 JAR)
install        →    install:install(安装到本地仓库)
deploy         →    deploy:deploy(发布到远程仓库)

执行过程

text
你执行:mvn package

Maven 执行:
1. 执行 compile 阶段 → compiler:compile 编译源码
2. 执行 test 阶段 → surefire:test 执行测试
3. 执行 package 阶段 → jar:jar 打包

自动按顺序执行,无需手动调用每个插件

插件配置示例

text
<build>
  <plugins>
    <!-- 配置编译插件 -->
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.8.1</version>
      <configuration>
        <source>17</source>     <!-- Java 源码版本 -->
        <target>17</target>     <!-- 编译输出版本 -->
        <encoding>UTF-8</encoding>
      </configuration>
    </plugin>
  </plugins>
</build>

常用内置插件

插件功能默认绑定阶段
maven-compiler-plugin编译源码compile
maven-surefire-plugin执行测试test
maven-jar-plugin打包 JARpackage
maven-war-plugin打包 WARpackage
maven-clean-plugin清理clean
maven-install-plugin安装到本地install
maven-deploy-plugin发布到远程deploy
maven-resources-plugin处理资源process-resources

生命周期(Lifecycle)

什么是生命周期

生命周期定义了构建阶段的顺序。Maven 有三个独立的生命周期:

text
Clean 生命周期:清理相关
  pre-clean → clean → post-clean

Default 生命周期:核心构建
  validate → compile → test → package → verify → install → deploy

Site 生命周期:文档生成
  pre-site → site → post-site → site-deploy

生命周期执行规则—— 核心

执行某个阶段时,会自动执行该阶段之前的所有阶段

text
mvn compile
# 执行:validate → compile

mvn test
# 执行:validate → compile → test-compile → test

mvn package
# 执行:validate → compile → test → package

mvn install
# 执行:validate → compile → test → package → verify → install

实际意义

  • 你不需要手动执行每个阶段
  • 只需要执行目标阶段,前置阶段自动执行
  • 确保构建流程完整

常用构建命令

命令执行的阶段产出
mvn compilevalidate → compiletarget/classes/*.class
mvn testcompile → testtarget/surefire-reports/测试报告
mvn packagecompile → test → packagetarget/*.jar 或 *.war
mvn installpackage → install本地仓库中的构件
mvn deployinstall → deploy远程仓库中的构件
mvn cleanclean删除 target 目录

组合命令

text
# 最常用的组合:清理后重新构建
mvn clean package     # 清理 + 编译 + 测试 + 打包
mvn clean install     # 清理 + 构建 + 安装到本地
mvn clean deploy      # 清理 + 构建 + 发布到远程

# 跳过测试(发布时常用)
mvn clean package -DskipTests

三大生命周期独立性

三个生命周期互不影响

text
mvn clean        # 只执行 clean 生命周期
mvn compile      # 只执行 default 生命周期
mvn site         # 只执行 site 生命周期

# 组合执行
mvn clean compile    # 先 clean,再 default
mvn clean package    # 先 clean,再 default 到 package

核心概念实际应用场景

场景1:新建 Maven 项目

text
步骤:
1. 确定项目坐标
   groupId: com.mycompany
   artifactId: my-project
   version: 1.0.0

2. 创建 pom.xml(POM概念)
   填入坐标,添加依赖

3. 添加依赖(依赖概念)
   Spring、JUnit 等

4. 执行构建(生命周期概念)
   mvn clean package

场景2:依赖版本冲突

text
问题:A 和 B 都依赖 C,但版本不同

理解概念后解决:
1. 知道依赖传递机制 → A 和 B 都会把 C 传给你
2. 知道版本选择规则 → 最短路径优先
3. 知道解决方法 → 直接声明版本或 exclusions

mvn dependency:tree  # 查看(依赖概念)
添加 exclusions      # 解决(依赖概念)

场景3:环境配置切换

text
需求:dev/test/prod 不同配置

理解概念后解决:
1. 知道 POM 可配置 properties
2. 知道 Profile 可激活不同配置
3. 使用 -Pdev 或 -Pprod 切换(Profile 概念)

场景4:自定义构建任务

text
需求:打包前执行代码生成

理解概念后解决:
1. 知道插件可执行任务
2. 知道插件可绑定到生命周期阶段
3. 配置插件绑定到 generate-sources 阶段(插件概念)

核心概念速查表

概念核心要点关键文件/命令
POM项目配置中心,继承超级 POMpom.xml、effective-pom
坐标GAV 唯一标识构件groupId:artifactId:version
依赖声明外部库,scope控制范围dependency、dependency:tree
插件执行构建任务,绑定到阶段plugins、compiler:compile
生命周期定义阶段顺序,触发前置阶段clean、compile、test、package

要点总结

  1. 五大概念相互关联:POM 是配置中心,坐标标识构件,依赖声明需求,插件执行任务,生命周期定义顺序
  2. POM 继承超级 POM:默认配置来自超级 POM,你只需覆盖需要的内容
  3. 坐标保证全球唯一:GAV 组合唯一标识一个构件
  4. scope 决定依赖可见性:compile 全程可见,test 仅测试,provided 不打包,runtime 运行时加载
  5. 依赖自动传递:间接依赖自动引入,用 dependency:tree 查看
  6. 插件执行具体任务:编译、测试、打包都是插件完成的
  7. 生命周期自动触发前置阶段:mvn package 自动执行 compile、test

📝 发现内容有误?点击此处直接编辑

← 上一篇 Maven 与 Ant/Gradle 对比
下一篇 → Maven 简介与安装配置
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库