Apache Maven 是 Java 生态系统中最流行的项目管理和构建自动化工具,通过约定优于配置(Convention Over Configuration)的理念,简化了 Java 项目的生命周期管理(编译、测试、打包、部署等)。
Maven 基于构建生命周期的核心概念。它本质上是一套标准化的、有序的构建步骤集合,定义了从项目源码到可部署工件(如 JAR、WAR 包)的完整过程。这种标准化解决了不同项目构建流程混乱、不一致的问题,让开发者能专注于业务逻辑而非构建细节。
一、Maven 构建生命周期
1、生命周期
生命周期(Lifecycle) 是 Maven 对 “项目处理过程” 的总称,涵盖了从项目初始化、构建、测试、文档生成到部署的所有标准化流程。Maven 中定义了3 个标准生命周期,分别处理不同维度的任务,每个生命周期包含多个阶段(Phase),按顺序执行。
(1)Clean 生命周期
负责清理项目:删除上一次构建生成的文件(如 class 文件、打包产物等),确保构建环境干净。主要阶段(顺序执行):
pre-clean
:清理前的准备工作(如备份文件)。clean
:删除上一次构建生成的目录(默认是target/
目录)。post-clean
:清理后的收尾工作(如记录清理日志)。
(2)Default 生命周期(核心)
构建项目的主要流程,负责核心构建流程(编译、测试、打包、部署等)。详细可见生命周期参考,常用阶段按执行顺序如下:
validate
:验证项目是否完整(如检查必要的配置文件、依赖是否存在)。compile
:编译项目主源码(将src/main/java下的 Java 文件编译为 class 文件,输出到target/classes)。test
:运行单元测试(执行src/test/java下的测试用例,依赖compile阶段)。package
:将编译后的 class 文件打包为可分发的工件(如 JAR、WAR,输出到target/目录)。install
<:将打包好的工件安装到本地 Maven 仓库(~/.m2/repository),供本地其他项目依赖。deploy
:将工件部署到远程 Maven 仓库,供团队其他成员或生产环境使用(依赖install阶段)。
PS:【执行规则】若执行某个阶段,其前面的所有阶段会自动依次执行。例如,执行mvn install
时,会自动执行validate → compile → test → package → install
。
(3)Site 生命周期
负责生成项目文档和站点(如 API 文档、项目说明、测试报告等)。主要阶段(顺序执行):
pre-site
:生成站点前的准备工作(如收集文档素材)。site
:生成站点文档(默认包含 HTML 格式的项目信息、依赖列表等)。post-site
:生成站点后的处理(如检查文档完整性)。site-deploy
:将生成的站点文档部署到远程服务器(如公司内网的文档服务器)。
示例命令
mvn clean package # 清理并打包项目
mvn install # 编译、测试并安装到本地仓库
mvn deploy # 部署到远程仓库
构建生命周期(Build Lifecycle)
指的是从源码到最终可交付产物的 一系列有序的、固定的阶段 。通常特指上述 3 个生命周期中的Default 生命周期,是 Maven 最核心的部分,直接对应 “从源码到可部署工件” 的构建过程(如编译、打包、安装、部署)。它是 “生命周期” 概念中与 “构建” 最相关的部分。
2、Maven 在生命周期基础上做了什么?
Maven 的核心价值之一在于其标准化的生命周期(Lifecycle),它定义了项目构建的完整流程(如清洁、编译、测试、打包、部署等)。但 Maven 并未止步于“定义生命周期”,而是在此基础上通过一系列机制实现了生命周期的可执行性、可扩展性和标准化,让构建过程更高效、更灵活。
(1)用“插件机制”实现生命周期的具体功能
Maven 的生命周期仅定义了“要做什么”(如“编译”“测试”),但并未实现“怎么做”。真正执行这些操作的是 Maven 插件(Plugin),而 Maven 通过“阶段与插件目标的绑定”将二者关联。
- 核心逻辑:生命周期的每个阶段(Phase)都绑定了一个或多个插件的“目标(Goal)”,插件目标负责具体的操作。
- Maven 为常见的构建任务提供了默认插件绑定,例如:
default
生命周期的compile
阶段(编译主代码)绑定了maven-compiler-plugin:compile
目标;test
阶段(执行测试)绑定了maven-surefire-plugin:test
目标;package
阶段(打包)绑定了maven-jar-plugin:jar
目标(Java 项目)。
Maven 允许用户自定义阶段与插件目标的绑定,以扩展生命周期的功能。例如:
- 默认情况下,
package
阶段对 Java 项目生成JAR
包(通过maven-jar-plugin
),但如果是 Web 项目,可绑定maven-war-plugin
的war
目标,让package
阶段生成WAR
包; - 还可通过
executions
配置,将自定义插件目标绑定到任意阶段(如在package
后自动执行代码质量检查插件)。
<build>
<plugins>
<!-- SonarQube 代码质量检查插件 -->
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1.2184</version>
<!-- 自定义执行配置:绑定到 package 阶段之后 -->
<executions>
<execution>
<!-- 执行的唯一标识(可自定义) -->
<id>sonar-after-package</id>
<!-- 绑定到 package 阶段,会在 package 完成后执行 -->
<phase>package</phase>
<!-- 指定要执行的插件目标 -->
<goals>
<goal>sonar</goal> <!-- SonarQube 插件的核心目标 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
(2)标准化“项目结构”,适配生命周期的执行
为了让生命周期的各个阶段能“准确找到所需资源”,Maven 定义了标准化的项目目录结构,并与生命周期阶段强关联。
例如:
- 主代码目录
src/main/java
对应compile
阶段的编译源; - 测试代码目录
src/test/java
对应test-compile
阶段的编译源; - 资源文件目录
src/main/resources
对应process-resources
阶段的资源复制; - 约定输出目录为
target
,compile
阶段输出到target/classes/
、test-compile
阶段输出到target/test-classes/
、package
阶段打包生成的 JAR/WAR 等文件会直接存放在target/
根目录下等。
这种标准化让生命周期的每个阶段无需手动配置路径,直接按约定找到资源,实现了“约定优于配置”(Convention over Configuration)。
(3)依赖管理:为生命周期提供“资源支持”
生命周期的多个阶段(如编译、测试、运行)都需要依赖外部库(如 JAR
包)。Maven 构建了一个完整的仓库体系,并在生命周期基础上整合了依赖管理机制,自动为各阶段提供所需资源:
- 依赖自动引入:通过
pom.xml
声明依赖后,Maven 会在compile
阶段自动从仓库下载依赖,并添加到类路径; - 依赖传递与冲突解决:自动处理依赖的传递性(如 A 依赖 B,B 依赖 C,则 A 自动依赖 C),并通过“就近原则”“声明优先”等规则解决版本冲突,确保生命周期各阶段(如编译、测试)能正确引用依赖。
(4)生命周期的“阶段顺序”与“自动触发”
Maven 的生命周期阶段按固定顺序执行,且“前序阶段完成后才会执行后续阶段”。例如:
- 执行
mvn package
(打包)时,Maven 会自动先执行其前序阶段:validate
→initialize
→compile
→test-compile
→test
→package
; - 不同生命周期相互独立,但可通过命令同时触发(如mvn clean install会先执行clean生命周期的所有阶段,再执行default生命周期到install的阶段)
这种“自动触发”机制避免了手动执行每个阶段的繁琐,确保构建流程的完整性(如打包前必须先通过测试)。
在此基础上,Maven 还支持阶段的部分执行(如只执行 mvn test
跳过打包),兼顾灵活性。
(5)结合“继承与聚合”,支持多模块项目的生命周期管理
在多模块项目中,Maven 的继承(Inheritance)和聚合(Aggregation)机制让生命周期更高效:
- 继承:子项目可继承父项目的生命周期配置(如插件版本、阶段绑定),避免重复配置;
- 聚合:通过
modules
声明模块依赖,执行根项目的生命周期阶段(如mvn install
)时,Maven 会按依赖顺序自动执行所有子模块的对应阶段(如先构建被依赖的模块,再构建依赖它的模块)。
二、POM(Project Object Model)
Maven 的核心是 pom.xml 文件,它定义了项目的元数据、依赖、插件和构建配置:
1、pom 文件基本构成
<!-- 根元素是 <project>,所有配置都嵌套在其中。根元素必须声明 Maven 的 XML 命名空间
xmlns="http://maven.apache.org/POM/4.0.0":指定 Maven POM 的版本(当前最新为 4.0.0)。
schemaLocation:指定 XML schema 位置,用于验证 POM 格式的合法性。
-->
<?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">
<!-- 指定 POM 模型版本,必须为 4.0.0(Maven 2/3 通用) -->
<modelVersion>4.0.0</modelVersion>
<!-- 项目坐标GAV(唯一标识)
Maven 通过 GroupId、ArtifactId、Version(简称 GAV)唯一标识一个项目,是依赖管理的基础。
- <groupId>:组织/公司标识(通常用反向域名,如 com.example)。
- <artifactId>:项目/模块名称(如 user-service)。
- <version>:项目版本(如 1.0.0、1.0.0-SNAPSHOT,SNAPSHOT 表示快照版本)。
-->
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<!-- 可选基本信息
- <name>:项目名称(可读性标识,非唯一)。
- <description>:项目描述。
- <url>:项目官方网站地址。
- <inceptionYear>:项目创建年份。
-->
<name>Demo Project</name>
<description>A sample Maven project</description>
<url>https://example.com/demo</url>
<inceptionYear>2025</inceptionYear>
<!-- 依赖管理 -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.23</version>
</dependency>
</dependencies>
<!-- 构建配置 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、依赖管理
Maven 通过中央仓库(https://repo.maven.apache.org/maven2)自动下载依赖,支持:
- 传递依赖:自动解析依赖的依赖(如
spring-core
依赖commons-logging
)。 - 依赖范围(Scope):控制依赖在不同阶段的可用性(如
compile
、test
、runtime
)。 - 依赖排除:排除不需要的传递依赖(如
exclusions
标签)。
(1)<dependencies>
:直接依赖
声明项目运行或编译时需要的具体依赖,Maven 会自动从仓库下载并加入类路径。
<dependencies>
<!-- 引入 Spring Boot 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.0</version>
</dependency>
<!-- 引入 JUnit 测试依赖(仅测试时生效) -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope> <!-- 依赖范围 -->
</dependency>
</dependencies>
依赖范围(Scope)
控制依赖在哪些生命周期阶段生效,常用值:
范围 | 编译 | 测试 | 运行 | 打包 | 示例 |
---|---|---|---|---|---|
compile | ✅ | ✅ | ✅ | ✅ | Spring、Hibernate 等 |
test | ❌ | ✅ | ❌ | ❌ | JUnit、Mockito |
runtime | ❌ | ✅ | ✅ | ✅ | JDBC 驱动(运行时需要) |
provided | ✅ | ✅ | ❌ | ❌ | Servlet API(容器已提供) |
system | ✅ | ✅ | ❌ | ❌ | 本地 JAR(需指定路径) |
(2)<dependencyManagement>
:依赖版本管理
用于统一管理依赖版本,仅声明版本,不实际引入依赖,子项目可通过 groupId
和 artifactId
继承版本,避免版本冲突。
<!-- 父项目 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.0</version> <!-- 统一版本 -->
</dependency>
</dependencies>
</dependencyManagement>
<!-- 子项目引用时无需指定版本 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <!-- 继承父 POM 版本 -->
</dependency>
</dependencies>
(3)依赖冲突
Maven 会自动引入直接依赖的 “依赖”(即传递依赖),形成依赖树。错误的版本可能导致类找不到(ClassNotFoundException
)、方法不兼容等问题。当多个依赖引入同一库的不同版本时,Maven 按以下规则处理:
- 路径最短优先:选择依赖树中层级浅的版本(如
A → B → X:1.0
和A → X:2.0
,选2.0
)。 - 声明顺序优先:若路径相同,先声明的依赖优先。
当默认规则不符合需求时,需手动干预,常用方法如下:
在引入冲突依赖的地方,排除低版本或不兼容的传递依赖。
exclusion
不需要指定版本,只需groupId
和artifactId
,因为要排除的是该依赖的所有版本。
<!-- 项目依赖 A 和 B,A 引入的 C-1.0 有问题,需排除 C-1.0,保留 B 引入的 C-2.0: -->
<dependencies>
<!-- 依赖 A,排除其传递的 C-1.0 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>A</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<!-- 必须精确匹配 C 的 groupId 和 artifactId -->
<groupId>com.example</groupId>
<artifactId>C</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 依赖 B,其传递的 C-2.0 会被保留 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>B</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
在 pom.xml
中直接声明冲突依赖的目标版本,使其成为 “直接依赖”(路径长度为 1),覆盖传递依赖的版本。
- 适用于:明确知道需要哪个版本,且该版本兼容所有依赖它的库。
<!-- 项目依赖 A 和 B,A 引入的 C-1.0 有问题,需排除 C-1.0,保留 B 引入的 C-2.0: -->
<dependencies>
<!-- 直接声明 C-2.0,路径长度 1,优先级最高 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>C</artifactId>
<version>2.0</version>
</dependency>
<!-- A 和 B 的依赖照常声明,其传递的 C 会被覆盖 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>A</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>B</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
在多模块项目中,通过父 POM 的 <dependencyManagement>
统一管理依赖版本,子模块继承后无需重复声明版本,避免冲突。
- 集中管理版本,修改时只需改父 POM,适用于大型项目。
<!-- 父 POM 配置 -->
<dependencyManagement>
<dependencies>
<!-- 统一 C 的版本为 2.0 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>C</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 子模块引用(无需指定版本,自动继承 2.0) -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>C</artifactId> <!-- 版本继承自父 POM 的 dependencyManagement -->
</dependency>
</dependencies>
3、构建配置
定义项目构建的规则,包括插件配置、资源目录、输出目录等。主要通过pom.xml
中的<build>
元素实现。<合理的构建配置能自动化完成编译、测试、打包等生命周期阶段的任务。
(1)基础构建配置
<build>
是 Maven 构建配置的根元素,包含全局构建配置和插件配置。
<project>
<!-- 其他配置…… -->
<!-- 构建配置 -->
<build>
<!-- 输出目录(默认 target/) -->
<directory>target</directory>
<!-- 打包后的文件名(不含扩展名) -->
<finalName>${project.artifactId}-${project.version}</finalName>
<!-- 源码目录(默认 src/main/java) -->
<sourceDirectory>src/main/java</sourceDirectory>
<!-- 测试源码目录(默认 src/test/java) -->
<testSourceDirectory>src/test/java</testSourceDirectory>
<!-- 资源文件目录(默认 src/main/resources) -->
<resources>
<resource>
<directory>src/main/resources</directory>
<!-- 是否过滤资源文件(替换 ${property} 占位符)(默认 true)
资源文件中的 ${property} 占位符会被 pom.xml 中 <properties> 定义的属性替换(如 ${project.version} 替换为项目版本)。
-->
<filtering>true</filtering>
<!-- 包含/排除特定文件(可选) -->
<includes>
<include>*.properties</include>
<include>*.xml</include>
</includes>
<excludes>
<exclude>*.txt</exclude>
</excludes>
</resource>
</resources>
<!-- 测试资源文件目录 -->
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
<!-- 3. 插件配置 -->
<plugins>...</plugins>
<pluginManagement>...</pluginManagement>
</build>
</project>
(2)插件配置
Maven 通过插件执行具体任务,每个插件包含多个目标(Goal)。<plugins>
用于配置项目使用的插件。
1)基本配置示例:配置编译插件(指定 JDK 版本)
<build>
<plugins>
<plugin>
<!-- 插件坐标(GAV) -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <!-- 插件版本 -->
<configuration>
<!-- 配置插件参数:指定 JDK 版本 -->
<source>1.8</source> <!-- 源码兼容版本 -->
<target>1.8</target> <!-- 编译输出版本 -->
</configuration>
</plugin>
</plugins>
</build>
2)插件目标绑定到生命周期阶段:
通过 <executions>
将插件目标(Goal)绑定到生命周期阶段(Phase):
<plugins>
<!-- 执行 mvn package 时,会自动触发 javadoc 目标,在 target/docs 生成 API 文档。 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.1</version>
<!-- 执行配置:绑定目标到阶段 -->
<executions>
<execution>
<id>generate-docs</id> <!-- 唯一标识(自定义) -->
<phase>package</phase> <!-- 绑定到 package 阶段 -->
<goals>
<goal>javadoc</goal> <!-- 执行的插件目标 -->
</goals>
<!-- 目标的参数配置(可选) -->
<configuration>
<destDir>${project.build.directory}/docs</destDir> <!-- 文档输出目录 -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
3)<pluginManagement>
:统一管理插件版本
类似 <dependencyManagement>
,用于声明插件的版本和默认配置,但不实际启用插件。子项目或当前项目的 <plugins>
中引用插件时,可省略版本,直接继承配置。适用于多模块项目(父 POM 中定义)。
4)常用插件
- 编译插件:
maven-compiler-plugin
(配置 JDK 版本)。 - 测试插件:
maven-surefire-plugin
(配置测试框架)。 - 打包插件:
maven-jar-plugin
(JAR 打包)、maven-war-plugin
(WAR 打包)。 - 资源插件:
maven-resources-plugin
(处理资源文件)。
<!-- 打包插件(maven-jar-plugin),自定义 JAR 包的清单文件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath> <!-- 自动添加依赖到类路径 -->
<mainClass>com.example.DemoMain</mainClass> <!-- 主类(可执行 JAR) -->
</manifest>
</archive>
</configuration>
</plugin>
<!-- 测试插件(maven-surefire-plugin),配置单元测试(如跳过测试、指定测试类) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<skipTests>false</skipTests> <!-- 是否跳过测试(true 则不执行测试) -->
<includes>
<include>**/*Test.java</include> <!-- 包含的测试类 -->
</includes>
<excludes>
<exclude>**/*IntegrationTest.java</exclude> <!-- 排除的测试类 -->
</excludes>
</configuration>
</plugin>
<!-- 资源插件(maven-resources-plugin),处理资源文件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<!-- 资源文件编码(避免中文乱码) -->
<encoding>UTF-8</encoding>
</configuration>
<executions>
<!-- 配置主资源处理(绑定到 process-resources 阶段) -->
<execution>
<id>copy-main-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal> <!-- 执行复制资源目标 -->
</goals>
<configuration>
<!-- 输出目录(主资源最终位置) -->
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<!-- 自定义主资源目录 -->
<resources>
<resource>
<directory>src/main/config</directory> <!-- 资源源目录 -->
<includes>
<include>*.properties</include> <!-- 只包含 properties 文件 -->
<include>*.xml</include> <!-- 只包含 xml 文件 -->
</includes>
<excludes>
<exclude>*.txt</exclude> <!-- 排除 txt 文件 -->
</excludes>
</resource>
</resources>
</configuration>
</execution>
<!-- 配置测试资源处理(绑定到 process-test-resources 阶段) -->
<execution>
<id>copy-test-resources</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<!-- 测试资源输出目录 -->
<outputDirectory>${project.build.testOutputDirectory}</outputDirectory>
<!-- 自定义测试资源目录 -->
<resources>
<resource>
<directory>src/test/config</directory>
<filtering>true</filtering> <!-- 开启测试资源过滤 -->
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
4、属性
Maven 中的 <properties>
元素用于定义键值对形式的属性,是项目配置的重要机制。它的核心作用是集中管理可复用的值(如版本号、路径、编码等),提高 pom.xml
的可维护性和灵活性。
(1)基本使用
<properties>
<java.version>1.8</java.version>
<spring.version>2.7.0</spring.version> <!-- 定义属性:spring版本 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- 内置属性:源码编码 -->
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version> <!-- 使用属性 -->
</dependency>
</dependencies>
(2)属性的分类
1)自定义属性
用户在<properties>
中手动定义的属性,用于统一管理项目中的可变值(如版本号、路径等)。
2)内置属性(Project Properties)
Maven 预定义的属性,对应项目自身信息,无需手动定义,直接引用即可。常用内置属性:
属性名 | 含义 | 示例值 |
---|---|---|
${project.groupId} | 项目的 groupId | com.example |
${project.artifactId} | 项目的 artifactId | demo-project |
${project.version} | 项目的版本 | 1.0.0-SNAPSHOT |
${project.name} | 项目名称(<name> 定义) | Demo Project |
${project.basedir} | 项目根目录(pom.xml 所在目录) | /Users/dev/demo-project |
${project.build.directory} | 构建输出目录(默认 target ) | /Users/dev/demo-project/target |
${project.build.outputDirectory} | 主类输出目录(默认 target/classes ) | target/classes |
3)Settings 属性
与 Maven 全局配置(settings.xml
)相关的属性,格式为 ${settings.xxx}
,例如:
${settings.localRepository}
:本地仓库路径(默认~/.m2/repository
)${settings.proxies}
:代理配置等(较少直接使用)
4)系统属性
Java 系统属性(可通过 java -Dkey=value
传入)和 Maven 运行时的系统属性,例如:
${user.home}
:当前用户的主目录${os.name}
:操作系统名称- 自定义系统属性:
mvn clean package -Denv=prod
,在pom.xml
中通过${env}
引用
5)环境变量属性
操作系统的环境变量,通过 ${env.ENV_NAME}
引用(注意:env
前缀固定),例如:
${env.JAVA_HOME}
:引用系统的JAVA_HOME
环境变量${env.PATH}
:引用系统的PATH
环境变量
(3)注意
- 属性名大小写敏感:
${java.version}
和${Java.Version}
是不同的属性。 - 优先级:系统属性(
-D
传入) > 自定义属性 > 内置属性。 - 避免循环依赖:属性值不能引用自身或形成循环(如
<a>${b}</a> <b>${a}</b>
)。 - 继承性:子项目会继承父项目
<properties>
中定义的属性,可在子项目中覆盖。
5、其它
(1)打包类型(<packaging>
)
指定项目打包后的产物类型,默认 jar
:
jar
:Java 项目,打包为 JAR 包。war
:Web 项目,打包为 WAR 包。pom
:父项目或聚合项目(无代码,仅用于管理)。ear
:企业级应用,打包为 EAR 包(少见)。
<packaging>war</packaging>
三、Maven 仓库管理
Maven 通过仓库管理依赖和项目构件。
依赖查找顺序
本地仓库 → 镜像仓库(若配置) →
**pom.xml**
** 中配置的远程仓库** → 中央仓库(默认)。
1、仓库类型
(1)本地仓库
默认位于 ~/.m2/repository
,存储已下载的依赖和本地安装的构件(通过 mvn install
安装)。避免重复下载,加速构建过程。
(2)远程仓库
- 中央仓库:Maven 官方仓库(https://repo.maven.apache.org/maven2)。
- 镜像仓库:如阿里云镜像(https://maven.aliyun.com/repository/central)。
- 私有仓库:企业自行搭建(如 Nexus、Artifactory),用于存储内部开发的组件、第三方付费库,或缓存中央仓库资源。
2、全局配置
在 Maven 全局配置文件中配置,对所有项目生效。settings.xml
有两个位置:
- 全局:
${M2_HOME}/conf/settings.xml
(影响所有用户); - 用户级:
${user.home}/.m2/settings.xml
(仅影响当前用户,优先级更高)
<settings>
<mirrors>
<!-- 阿里云镜像(优先于中央仓库) -->
<mirror>
<id>aliyun-mirror</id>
<mirrorOf>central</mirrorOf> <!-- 镜像中央仓库 -->
<name>Aliyun Mirror for Central</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
<!-- 企业私服镜像(镜像所有仓库) -->
<mirror>
<id>company-mirror</id>
<mirrorOf>*</mirrorOf> <!-- * 表示镜像所有仓库 -->
<url>http://nexus.company.com/repository/maven-public/</url>
</mirror>
</mirrors>
<!-- 若私服需要账号密码,在 servers 中配置认证: -->
<servers>
<server>
<id>company-mirror</id> <!-- 必须与仓库的 <id> 一致 -->
<username>your-username</username>
<password>your-password</password>
</server>
</servers>
</settings>
其中,<mirrorOf>
标签取值:
- `central`:仅镜像中央仓库;
- `repo1,repo2`:镜像指定仓库(多个用逗号分隔);
- `*`:镜像所有仓库(私服常用);
- `!repo1`:镜像除 `repo1` 外的所有仓库。
3、项目级配置
在单个项目的 pom.xml
中配置,仅对当前项目生效。
在 Maven 的
pom.xml
中不能直接配置私服的认证信息 (用户名 / 密码等校验信息)。Maven 规定,私服的认证信息必须配置在**settings.xml**
中,而pom.xml
仅用于声明仓库地址。
配置依赖仓库(<repositories>
):
<repositories>
<!-- 阿里云仓库(替代中央仓库,国内速度快) -->
<repository>
<id>aliyun-public</id> <!-- 仓库唯一标识 -->
<name>Aliyun Public Repository</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled> <!-- 是否启用发布版本(稳定版) -->
</releases>
<snapshots>
<enabled>false</enabled> <!-- 是否启用快照版本(开发版) -->
</snapshots>
</repository>
</repositories>
插件仓库(<pluginRepositories>
):
插件仓库与依赖仓库分开配置,(格式与 <repositories>
相同):
<pluginRepositories>
<pluginRepository>
<id>aliyun-plugin</id>
<url>https://maven.aliyun.com/repository/public</url>
</pluginRepository>
</pluginRepositories>
4、发布项目到仓库
通过 mvn deploy
命令可将项目打包后发布到远程仓库(通常是私服),需在 pom.xml
中配置发布地址:
<distributionManagement>
<!-- 发布发布版本(稳定版)到 releases 仓库 -->
<repository>
<id>company-releases</id> <!-- 与 settings.xml 中 server 的 id 一致 -->
<name>Company Releases Repository</name>
<url>http://nexus.company.com/repository/maven-releases/</url>
</repository>
<!-- 发布快照版本(开发版)到 snapshots 仓库 -->
<snapshotRepository>
<id>company-snapshots</id>
<name>Company Snapshots Repository</name>
<url>http://nexus.company.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
- 版本号带
-SNAPSHOT
的项目会发布到<snapshotRepository>
,否则发布到<repository>
。
四、多模块项目
Maven 支持将大型项目拆分为多个模块,每个模块有独立的 POM,通过父 POM 统一管理。子项目可继承父项目的配置(如依赖版本、插件配置等),减少重复配置。
目录结构:
my-project/
├── pom.xml # 父 POM
├── module-api/ # API 模块
│ └── pom.xml
├── module-service/ # 服务模块
│ └── pom.xml
└── module-web/ # Web 模块
└── pom.xml
1、项目继承(Inheritance):复用配置,减少重复
项目继承核心是让子项目复用父项目的配置,避免重复定义(如依赖版本、插件配置、属性等)。
- 抽取多模块项目的通用配置(如依赖版本、插件、编码格式等)到父项目,子项目直接继承,减少冗余。
- 统一管理项目版本、依赖版本,避免版本混乱。
(1)可继承的配置项
子项目会自动继承父项目的以下配置(可在子项目中覆盖):
groupId
、version
(子项目可省略,直接继承);properties
(属性);dependencyManagement
(依赖版本管理);pluginManagement
(插件版本和配置管理);repositories
、pluginRepositories
(仓库配置);build
中的部分配置(如源码目录、输出目录等)。
(2)实现
父项目 POM:
- 打包类型为
pom
(唯一允许被继承的类型) - 定义通用配置(如
dependencyManagement
、pluginManagement
、properties
等)。
<?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>parent-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging> <!-- 父项目必须为 pom 类型 -->
<name>Parent Project</name>
<!-- 通用属性(子项目可继承) -->
<properties>
<java.version>1.8</java.version>
<spring.boot.version>2.7.0</spring.boot.version>
</properties>
<!-- 统一管理依赖版本(子项目引用时无需指定版本) -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 统一管理插件(子项目可继承配置) -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
子项目通过<parent>
标签指定父项目,继承其配置:
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<!-- 父项目 pom.xml 路径(默认 ../pom.xml) -->
<relativePath>../parent/pom.xml</relativePath>
</parent>
<!-- 子项目自身坐标(可省略 groupId 和 version,继承父项目) -->
<artifactId>module-api</artifactId>
<!-- 引用父项目管理的依赖(无需指定版本) -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <!-- 版本继承自父项目 -->
</dependency>
</dependencies>
<!-- 继承父项目的插件配置(无需重复定义版本和基础配置) -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <!-- 配置继承自父项目的 pluginManagement -->
</plugin>
</plugins>
</build>
2、项目聚合(Aggregation):批量构建多模块
多模块项目中,通过一个 “父项目” 将多个子模块(Module)聚合在一起,实现 “一键构建所有模块”,无需逐个处理子模块。
(1)作用
- 简化多模块项目的构建流程:执行父项目的 Maven 命令(如
mvn clean install
),会自动按依赖顺序构建所有子模块。 - 明确模块间的关系:父项目作为 “容器”,统一管理子模块。
(2)实现
父项目 pom.xml
:通过 <modules>
标签列出所有子模块(子模块的相对路径)。
<?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>parent-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging> <!-- 父项目必须为 pom 类型 -->
<name>Parent Project</name>
<!-- 声明子模块(相对路径,指向子模块目录) -->
<modules>
<module>module-api</module> <!-- 子模块 1 -->
<module>module-service</module> <!-- 子模块 2 -->
<module>module-web</module> <!-- 子模块 3 -->
</modules>
</project>
子模块的 pom.xm
无需特殊配置(可独立构建),通常会放在父项目的子目录中,目录名与<module>
标签指定的名称一致。
(3)构建规则
- 执行父项目的 Maven 命令(如
mvn package
)时,Maven 会自动按依赖顺序构建子模块:若module-web
依赖module-service
,则先构建module-service
,再构建module-web
。 - 子模块可单独构建(进入子模块目录执行
mvn
命令),不影响其他模块。
五、常用命令
1、常用命令
mvn clean # 清理项目
mvn compile # 编译源代码
mvn test # 运行测试
mvn package # 打包项目(JAR/WAR)
mvn install # 安装到本地仓库
mvn deploy # 部署到远程仓库
mvn dependency:tree # 查看依赖树
mvn archetype:generate # 创建项目骨架
2、跳过测试
mvn package -DskipTests # 不执行测试用例,但编译测试代码
mvn package -Dmaven.test.skip=true # 不执行测试用例,且不编译测试代码
3、查看依赖树
除了命令行,主流 IDE 提供了更直观的可视化依赖树,如 IntelliJ IDEA 中提供了
Show Dependencies
,会显示图形化依赖树,冲突依赖会标红。
在项目根目录(pom.xml
所在目录)执行以下命令,会打印项目的完整依赖树,包括直接依赖和传递依赖。
mvn dependency:tree
输出:
[INFO] com.example:demo:jar:1.0.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.7.0:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.7.0:compile
[INFO] | | +- org.springframework.boot:spring-boot:jar:2.7.0:compile
[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:2.7.0:compile
[INFO] | | \- ...
[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:2.7.0:compile
[INFO] | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.13.3:compile
[INFO] | | \- ...
[INFO] | \- ...
[INFO] \- junit:junit:jar:4.13.2:test
- 树结构中,
+
表示直接依赖,|
和\-
表示传递依赖的层级关系; compile
、test
等表示依赖范围(<scope>
)。
(1)常用参数:过滤和筛选
当项目依赖较多时,可通过参数过滤关键信息,提高分析效率。
1)按依赖名过滤(查找特定依赖)
使用 grep
(Linux/Mac)或 findstr
(Windows)筛选包含指定 artifactId
的依赖:
# Linux/Mac:查找包含 "jackson" 的依赖
mvn dependency:tree | grep "jackson"
# Windows:查找包含 "jackson" 的依赖
mvn dependency:tree | findstr "jackson"
2)查看依赖冲突
添加 -Dverbose
参数,可显示被排除的冲突依赖(标记为 omitted for conflict with
):
mvn dependency:tree -Dverbose
输出:
[INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar:2.13.3:compile
[INFO] | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.13.3:compile
[INFO] | | \- com.fasterxml.jackson.core:jackson-core:jar:2.13.3:compile
[INFO] | | \- (com.fasterxml.jackson:jackson-bom:pom:2.13.3:import - omitted for conflict with 2.12.7)
- 上述示例中,
jackson-bom:2.13.3
与2.12.7
冲突,Maven 选择了其中一个版本。
3)按依赖范围过滤
通过 -Dscope
参数仅显示指定范围的依赖(如 test
、compile
):
# 仅显示 test 范围的依赖
mvn dependency:tree -Dscope=test
(2)导出依赖树到文件
将依赖树输出到文本文件,方便保存和分析:
mvn dependency:tree > dependency-tree.txt