Maven 核心概念

FreeGuideOnline 最新 2026-07-15

xml org.springframework.boot spring-boot-starter-web 3.2.0


坐标是 Maven 一切操作的基础,查找依赖、发布构件全部依赖它。

### 依赖管理(Dependency)

依赖管理是 Maven 最常用的功能。你只需要声明“我需要什么”,Maven 会自动帮你去仓库下载并构建好 classpath。

#### 依赖范围(scope)

通过 `scope` 属性可以控制依赖在哪些 classpath 中生效:

- **compile**(默认):编译、测试、运行时都有效,会传递。
- **provided**:编译和测试时有效,运行时由容器提供(如 Servlet API)。
- **runtime**:运行和测试时有效,编译时不需要(如 JDBC 驱动)。
- **test**:仅测试阶段有效,如 JUnit。
- **system**:类似 provided,但必须显式指定本地路径,不推荐使用。

#### 依赖传递与冲突

A 依赖 B,B 依赖 C,那么 A 也会间接依赖 C。这称为传递性依赖。当多个传递路径引入同一个构件的不同版本时,Maven 采用如下规则仲裁:

1. **最短路径优先**:路径短的版本被选用。
2. **先声明优先**:路径长度相同时,POM 中先声明的那个版本获胜。

你可以使用 `exclusions` 显式排除某个传递依赖:

```xml
<dependency>
  <groupId>com.example</groupId>
  <artifactId>A</artifactId>
  <exclusions>
    <exclusion>
      <groupId>com.unwanted</groupId>
      <artifactId>unwanted-lib</artifactId>
    </exclusion>
  </exclusions>
</dependency>

依赖管理段(dependencyManagement)

在父 POM 中使用 dependencyManagement 可以统一声明依赖的版本,子模块继承后只需写 groupIdartifactId 即可,不用再写版本号,避免版本冲突。

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.30</version>
    </dependency>
  </dependencies>
</dependencyManagement>

仓库(Repository)

仓库就是存放构件的地方。Maven 的仓库分为本地仓库和远程仓库。

  • 本地仓库:默认为 ${user.home}/.m2/repository。所有构件会先下载到这里,构建时也从这里读取。
  • 远程仓库:包括中央仓库(Maven Central)和私有仓库(如 Nexus、Artifactory)。中央仓库是公共的,几乎包含所有开源构件。私服通常用于代理中央仓库、发布内部构件。

仓库的查找顺序为:本地仓库 → 私服 → 中央仓库。

你可以在 POM 或 settings.xml 中配置镜像和仓库地址:

<repositories>
  <repository>
    <id>aliyunmaven</id>
    <url>https://maven.aliyun.com/repository/public</url>
  </repository>
</repositories>

生命周期(Lifecycle)

Maven 的构建过程是围绕生命周期设计的。最核心的标准生命周期包含三个阶段:

  1. clean:清理项目,删除 target 目录。
  2. default:负责项目构建与部署,包含多个关键阶段。
  3. site:生成项目站点文档。

每个生命周期由若干个阶段(phase)按顺序组成。以 default 生命周期为例,执行 mvn install 时,会依次执行处理资源(resources)、编译(compile)、测试(test)、打包(package)、安装到本地仓库(install)等所有前置阶段。

关键阶段说明:

  • validate:验证项目是否正确且所有必要信息可用。
  • compile:编译项目主代码。
  • test:使用单元测试框架运行测试。
  • package:将编译后的代码打包成可分发格式,如 jar。
  • verify:运行集成测试检查,确保包有效。
  • install:将包安装到本地仓库,供其他项目本地引用。
  • deploy:将包复制到远程仓库,供其他开发者和项目共享。

你不需要记住所有阶段,只要理解:mvn 命令 其实是触发一个阶段的执行,该阶段之前的阶段会被自动顺序执行。

插件(Plugin)与目标(Goal)

生命周期本身只定义了“什么阶段做什么事”的抽象框架,具体工作由插件完成。每个 Maven 功能背后都有一个或多个插件。

  • 插件目标(Goal):一个插件可以有多个目标,每个目标就是一个具体的任务。例如 compiler:compile 是编译插件 maven-compiler-plugincompile 目标。
  • 生命周期阶段是与插件目标绑定的。比如 compile 阶段默认绑定了 maven-compiler-plugincompile 目标。

配置插件的方式通常是在 POM 的 <build><plugins> 中:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.11.0</version>
  <configuration>
    <source>17</source>
    <target>17</target>
  </configuration>
</plugin>

理解插件后,你就能明白所谓的“Maven 不能干某某事”其实只是没找到对应的插件和目标。

聚合与继承

多模块项目通过聚合与继承来统一管理。

聚合(Aggregation)

聚合模块负责将所有子模块组合在一起,以便一次性构建所有模块。只需在顶层 POM 中用 <modules> 列举子模块目录:

<modules>
  <module>module-a</module>
  <module>module-b</module>
</modules>

在聚合 POM 目录下运行 mvn install,Maven 会根据模块间依赖关系自动确定构建顺序。

继承(Inheritance)

继承解决了多个模块重复配置的问题。父 POM 定义公共配置,子模块通过 <parent> 引用即可。

父 POM 的 packaging 必须为 pom,子模块中引入:

<parent>
  <groupId>com.mycom</groupId>
  <artifactId>parent-project</artifactId>
  <version>1.0.0</version>
</parent>

子模块会继承父 POM 的 groupIdversion、属性(properties)、依赖管理(dependencyManagement)、插件配置等。relativePath 可以指定父 POM 的位置,默认是 ../pom.xml

很多时候,聚合和继承会共用一个根 POM:它既是父 POM(被继承),又是聚合 POM(管理模块),这是一个非常普遍的实践模式。

属性与资源过滤

Maven POM 中可以使用 <properties> 定义变量,方便统一管理版本号或配置。

<properties>
  <java.version>17</java.version>
  <spring.boot.version>3.2.0</spring.boot.version>
</properties>

变量可以在其他地方通过 ${java.version} 引用。结合资源过滤,你甚至可以将 POM 属性注入到 application.properties 等资源文件中。在 <build> 中开启过滤:

<resources>
  <resource>
    <directory>src/main/resources</directory>
    <filtering>true</filtering>
  </resource>
</resources>