S01-08 Servlet-Maven
[TOC]
概述
核心定义
Maven 是 Apache 软件基金会维护的开源 Java 项目管理与构建自动化工具。它以项目对象模型(Project Object Model, POM)为核心,将 Java 项目的编译、测试、打包、部署以及第三方依赖包管理整合为一套标准化的流水线作业。
诞生背景
在传统 Java 开发阶段(如早期通过手动管理 Jar 包或编写纯 Ant 脚本构建),开发流程面临三个痛点:
- Jar 包依赖混乱:三方库需手动下载并拷贝到工程
lib目录,容易引起版本漂移且代码仓库异常臃肿。 - 间接依赖冲突:类库之间的间接依赖容易导致运行时抛出
NoSuchMethodError或ClassNotFoundException。 - 构建规范割裂:各团队工程结构与编译脚本形式各异,新人接入和跨项目迁移成本高昂。
Maven 通过统一的元数据规范和中央化仓库机制,彻底替代了手工管理模式。
核心理念
Maven 遵循“约定优于配置”(Convention Over Configuration)的设计哲学。
传统构建工具需要手动指定源码路径、资源存放位置以及编译产物目录。Maven 预设了一套工业界通用的标准约定:
- 开发者遵循固定的目录层级存放代码与资源,无需编写脚本即可直接执行编译、打包等操作。
- 只有在项目有特殊定制需求(如更改源码编码、自定义打标行为)时,才需要在配置文件中显式覆盖默认规则。
基础结构
目录规范:
标准 Maven 工程遵循以下分层结构:
src/main/java:业务主代码。src/main/resources:业务主配置文件及静态资源。src/test/java:自动化测试用例源码。src/test/resources:测试专用的配置文件。target:临时编译产物与最终生成的打包文件(如 Jar、War)。pom.xml:项目对象模型描述文件,置于工程根目录。
最小配置:
每个 Maven 工程的核心都是根目录下的 pom.xml。一个最小可用工程仅需声明基本的坐标属性与打包格式:
<project xmlns="http://maven.apache.org/POM/4.0.0">
<!-- 声明工程的唯一坐标元数据 -->
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>quickstart-demo</artifactId>
<version>1.0.0</version>
<!-- 声明当前模块的输出包格式 -->
<packaging>jar</packaging>
</project>核心要素
Maven 将项目的元数据、外部依赖、仓库系统以及构建过程统一抽象并解耦:
- POM(项目对象模型):使用 XML 语言统一描述工程的静态元数据、外部类库依赖、开发者信息和插件配置。
- 依赖管理系统:通过
groupId、artifactId、version三元坐标唯一定位网络构件,并自动化处理依赖的树形传递与版本仲裁。 - 分级仓库体系:构建所需的构件按照“本地仓库 -> 局域网私服(Nexus) -> 互联网中央仓库(Maven Central)”的三级拓扑进行查找与落盘缓存。
- 构建生命周期:抽象出独立且标准的构建流程(
clean清理、default构建核心、site文档生成),使得不同的构建行为具备统一的操作界面。 - 插件驱动机制:Maven 核心程序仅负责生命周期调度与阶段驱动,实际的编译、测试、打包行为均委托给插件(Plugin)的目标(Goal)完成。

构建运转流程
在开发与持续集成场景中,构建动作由标准化流程按步执行:
配置读取与依赖仲裁:解析
pom.xml,校验工程结构规范,并向本地或远程仓库拉取解析依赖树。生命周期阶段驱动:当触发具体阶段命令(如
mvn package)时,Maven 按预设顺序自前向后执行前置阶段(如validate->compile->test->package)。插件任务派发:各个阶段依次唤醒其绑定的插件目标(如编译插件
maven-compiler-plugin),完成字节码生成、测试报告导出以及压缩归档。
安装与配置
Maven 基于 Java 平台运行,其安装本质是解压二进制包并配置系统 PATH 变量,核心配置则通过修改 settings.xml 来接管仓库路径、镜像分发与网络凭证。
环境准备
依赖需求
Maven 依靠 JDK 执行项目的编译与分析,安装前必须确保操作系统中已安装合适版本的 JDK(当前主流推荐 JDK 8、17 或更高版本)。
环境校验
在终端或控制台执行以下命令,确认系统已识别到有效的 Java 开发环境:
# 验证 JDK 是否安装以及环境变量是否生效
java -version
javac -version系统必须正确输出 Java 运行时版本号与编译器版本号,且系统环境变量中已配置指向 JDK 根目录的 JAVA_HOME。
下载解压
介质获取
访问 Apache Maven 官方下载页面,根据操作系统下载对应的二进制压缩包(Binary distribution):
- Windows 环境推荐下载:
apache-maven-x.y.z-bin.zip - Linux / macOS 环境推荐下载:
apache-maven-x.y.z-bin.tar.gz
目录结构
将下载的压缩文件解压至无中文字符、无空格的物理路径(如 /usr/local/apache-maven 或 C:\opt\apache-maven)。解压后的核心目录职责如下:
bin:包含可执行脚本(mvn、mvn.cmd)。boot:包含 Maven 内部类加载器依赖包(Plexus Classworlds)。conf:配置文件目录,包含全局核心配置settings.xml。lib:Maven 运行时依赖的核心 Jar 库。
环境变量
变量声明
为了让终端在任何工作目录下均能调用 mvn 命令,需要将 Maven 的 bin 路径注入系统全局环境变量。
多系统配置
Windows 系统:
- 打开“系统属性” -> “高级系统设置” -> “环境变量”。
- 新建系统变量:变量名设为
MAVEN_HOME,变量值填入 Maven 的解压根路径(如C:\opt\apache-maven-3.9.16)。 - 编辑
Path系统变量,添加新建项%MAVEN_HOME%\bin。
macOS / Linux 系统:
打开终端配置文件(如
~/.bashrc或~/.zshrc)。写入配置:
bashexport MAVEN_HOME=/usr/local/apache-maven-3.9.16 export PATH=$MAVEN_HOME/bin:$PATH执行
source ~/.zshrc或source ~/.bashrc使变更即刻生效。
终端验证
重新打开终端窗口,输入命令检测安装结果:
mvn -v若终端打印出 Maven 版本、Maven home 目录路径以及识别到的 Java runtime 版本,即表明全局安装成功。
基础配置
配置层级
Maven 配置中枢为 settings.xml,分为两个层级:
- 全局配置:位于 Maven 安装目录下的
conf/settings.xml,对使用该 Maven 实例的所有机器用户生效。 - 用户配置:位于用户主目录的
~/.m2/settings.xml,作用范围仅限于当前操作系统用户,且该配置会优先覆盖全局配置。推荐复制一份settings.xml至用户目录中按需修改。
本地仓库
Maven 默认将拉取的构件保存在系统盘用户目录(~/.m2/repository)中。为了防止系统盘空间不足,可在 settings.xml 中指定自定义磁盘路径:
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0">
<!-- 指定本地仓库存储依赖包的自定义物理路径 -->
<localRepository>/usr/local/maven-repository</localRepository>
</settings>镜像源加速
Maven 官方中央仓库服务器位于海外,国内下载构件易出现超时中断。通过在 <mirrors> 标签内配置公共镜像代理(如阿里云镜像服务),可大幅提升依赖下载速率:
<mirrors>
<!-- 配置中央仓库的国内镜像节点以加快依赖下载速度 -->
<mirror>
<id>aliyunmaven</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Public Mirror</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>进阶配置
编译环境统一
新版 Maven 默认的 Java 编译级别可能较低。为了避免每个子项目重复配置 maven-compiler-plugin,可在 settings.xml 中配置全局编译规范:
<profile>
<!-- 全局指定项目构建时默认使用的 Java 编译版本 -->
<id>jdk-17</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>17</jdk>
</activation>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
</properties>
</profile>私服认证
当企业内部搭建 Nexus 或 Artifactory 架构时,拉取和发布私有 Jar 包通常需要访问凭据。出于安全性考量,账号密码不应写入项目的 pom.xml,而应定义在 settings.xml 的 <servers> 模块中:
<servers>
<!-- 企业私有仓库 Nexus 的访问凭证 -->
<server>
<id>nexus-releases</id>
<username>deployment-user</username>
<password>SafePassword2026</password>
</server>
</servers>仓库检索流程
当项目声明构件依赖时,Maven 解析外部库的流转判定逻辑如下:
本地匹配:先检查本地仓库(
localRepository)是否存在该版本构件,若命中且校验通过直接使用。私服/Profile 检查:若本地无对应文件,按照
settings.xml中激活的私服或仓库列表发起拉取请求。镜像拦截:如果配置了匹配的
<mirrorOf>规则,请求将被转交至指定的 Mirror 节点。远程下载并落地缓存:构件自中央仓库或远程私服完成网络流传输,保存至本地缓存文件系统,以备后续工程离线复用。

工具集成
IDEA 设置
在现代化 IDE(如 IntelliJ IDEA)中,推荐将自带的 Bundled Maven 替换为本地配置好的实例,确保本地构建与开发工具表现一致:
打开
Settings(或Preferences) ->Build, Execution, Deployment->Build Tools->Maven。Maven home path:选择自定义安装解压的物理路径。
User settings file:勾选
Override,指定配置好的settings.xml文件。Local repository:勾选
Override,指向自定义本地仓库路径。
构建性能优化
在 settings.xml 同级目录或工程根目录建立 .mvn/maven.config 文件,可固化高频构建参数以加速执行:
- 并发多线程编译:输入
-T 1C(即按每核心 1 个线程并行构建模块)。 - 跳过无改动测试:添加
-DskipTests加快发布打包流程。
IDEA 工程构建
在 IntelliJ IDEA 中构建 Java SE 与 Java Web 工程,核心在于通过 Maven 统一工程模型,将编译、测试与打包完全托管于构建生命周期,摆脱繁琐的手动类库引用。
环境预设
全局环境隔离
在 IDEA 中配置 Maven 时,如果仅在打开的项目内修改配置,后续新建项目仍会重置为 IDEA 自带的 Bundled Maven。因此必须优先配置全局默认模板:
打开 IDEA 欢迎界面或顶部菜单栏,依次进入 File -> New Projects Setup -> Settings for New Projects。
展开左侧菜单至 Build, Execution, Deployment -> Build Tools -> Maven。
Maven home path:指定本地安装的 Maven 物理路径(如
/usr/local/apache-maven或自定义解压目录)。User settings file:勾选右侧 Override,选择定制后的
settings.xml。Local repository:勾选 Override,指定自定义的本地依赖缓存目录。
工程目录规范
无论是 SE 还是 Web 工程,IDEA 均严格遵循 Maven 标准目录组织规范:
src/main/java:编译为 class 字节码的业务源码目录(Sources Root)。src/main/resources:打包时自动输出至根类路径的资源文件(Resources Root)。src/test/java:仅在测试生命周期参与编译执行的用例目录(Test Sources Root)。pom.xml:模块的核心配置与坐标中枢。

SE 工程构建
空白创建方式
标准 Java SE 工程打包形态通常为 Jar 包,推荐采用轻量级直建流程:
点击 File -> New -> Project。
左侧生成器选择 Maven(不勾选任何 Archetype 原型模板)。
填入项目基础元数据:
- Name:工程模块名称(例如
se-demo)。 - Location:工程存放的本地物理目录。
- JDK:选择项目构建所使用的 Java 版本。
- Name:工程模块名称(例如
展开 Advanced Settings,设定当前工程的坐标属性:
GroupId:企业或组织域名反写(如com.example)。ArtifactId:模块唯一标识(如se-demo)。Version:初始版本号(默认1.0-SNAPSHOT)。
编码与生命周期
创建完毕后,在 src/main/java 下建立包名并新建启动类:
// 系统主程序执行入口
public static void main(String[] args) {
// 终端输出启动日志
System.out.println("Maven SE Project Started.");
}在右侧打开 Maven 工具窗口,双击展开 Lifecycle 模块:
- 双击
compile:编译源码至target/classes目录。 - 双击
package:自动执行编译与测试,在target目录下生成可分发的se-demo-1.0-SNAPSHOT.jar。
Web 工程构建
骨架与平滑升级
Java Web 工程的目标产物为 War 包,包含专属的动态发布资源目录(webapp)。构建 Web 工程主要有两种途径:
改造升级法(推荐):新建标准 SE 项目,在
pom.xml中将打包方式声明为war,再手动创建src/main/webapp/WEB-INF/web.xml目录与文件。该方式结构纯净,避开骨架下载卡顿。骨架创建法:新建项目时勾选原型模板
maven-archetype-webapp。骨架生成后通常缺失src/main/java与resources文件夹,需手动右键新建对应目录并分别标记为 Sources Root 与 Resources Root。
核心依赖与作用域
Web 工程必须依赖 Servlet API 进行接口开发。在 pom.xml 中引入依赖时,必须声明 <scope>provided</scope>:
<project>
<!-- 声明构建打包产物为 Web 应用专用的 war 包 -->
<packaging>war</packaging>
<dependencies>
<!-- 引入 Servlet 规范依赖并设置范围为 provided -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>依赖范围说明:若未设置
provided,Maven 打包时会将 Servlet API 打入 War 包内的WEB-INF/lib目录,部署到 Tomcat 等容器时会与容器自带的 API 产生双亲委派类加载冲突,导致服务异常。
运行与调试
插件驱动运行
无需在本地完整安装 Tomcat 容器,可以通过在 pom.xml 中集成嵌入式 Web 容器插件直接启动:
<plugins>
<!-- 配置嵌入式 Tomcat 插件实现无缝运行与热部署 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<!-- 设定服务端口与上下文根路径 -->
<configuration>
<port>8080</port>
<path>/</path>
</configuration>
</plugin>
</plugins>配置完成后,在 IDEA 终端执行 mvn tomcat7:run,或在右侧 Maven 插件窗口双击插件命令即可启动容器。
本地容器部署
在生产与严格调试环境中,通常使用本地独立部署的 Tomcat:
点击 IDEA 顶部 Run -> Edit Configurations。
点击左上角
+号,选择 Tomcat Server -> Local。在 Application server 栏选择本地解压的 Tomcat 根目录。
切换到 Deployment 标签页,点击
+选择 Artifact:- 选择带有
war exploded后缀的工件(解压目录形式),支持开发期类文件与静态页面热重载。 - 设定 Application context 访问上下文路径(例如
/api或/)。
- 选择带有
点击 Debug 模式运行,支持在代码中断点跟踪请求链路。
进阶调优与规范
打包插件配置
在基于注解的现代 Servlet 3.0+ 规范中,项目可以省去 web.xml 文件。为防止 maven-war-plugin 因缺少 web.xml 报错构建失败,需在 <build> 中添加保护配置:
<build>
<!-- 允许无 web.xml 情况下正常构建打出 war 包 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>依赖管理
Maven 的依赖管理通过统一的坐标系统定位构件,并借助树状解析引擎自动化处理第三方库的下载、传递、范围控制与版本冲突。
依赖基础
坐标定义
Maven 使用三维基础坐标(GAV)在仓库中唯一定位任何构件:
groupId:组织或公司的反向域名标识(如org.springframework)。artifactId:模块或项目的实际名称(如spring-core)。version:当前构件的具体发布版本号(如6.1.2)。
声明配置
在 pom.xml 中通过 <dependencies> 标签集中管理工程所需的所有直接依赖:
<dependencies>
<!-- 声明业务所需的核心依赖坐标 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.0.0-jre</version>
</dependency>
</dependencies>依赖范围
Classpath 控制
Java 在不同阶段使用不同的类路径(Classpath)。依赖范围(Scope)用于限制依赖项在编译(Compile)、测试(Test)、运行(Runtime)三种 Classpath 中的可用性。
范围规则
通过 <scope> 属性可为依赖指定以下六种范围:
| 依赖范围 (Scope) | 编译 Classpath | 测试 Classpath | 运行 Classpath | 打包进产物 | 典型示例 |
|---|---|---|---|---|---|
compile(默认) | 有效 | 有效 | 有效 | 是 | commons-lang3 基础工具库 |
provided | 有效 | 有效 | 无效 | 否 | jakarta.servlet-api,容器已内置 |
runtime | 无效 | 有效 | 有效 | 是 | mysql-connector-j,仅运行时反射加载 |
test | 无效 | 有效 | 无效 | 否 | junit-jupiter,仅测试阶段运行 |
system | 有效 | 有效 | 无效 | 否 | 本地绝对路径引入的非仓库 Jar 包 |
import | 无效 | 无效 | 无效 | 否 | 仅在 dependencyManagement 中导入 BOM |
依赖传递
传递机制
当工程 A 显式引入构件 B,而构件 B 本身依赖构件 C 时,Maven 会自动将构件 C 解析并加入工程 A 的依赖链路中,形成依赖树结构。

可选依赖与排除
当不希望某个依赖向下游工程自动传递时,可通过可选标记或显式排除进行拦截:
可选依赖(Optional):由构件的维护方声明。设置
<optional>true</optional>后,下游项目默认不引入此依赖,下游若需使用必须显式在自身pom.xml中声明。依赖排除(Exclusion):由当前项目的消费者声明。使用
<exclusions>强制阻断上游依赖携带的特定传递性构件。xml<dependency> <!-- 引入第三方客户端并声明为可选依赖 --> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>5.6.0</version> <optional>true</optional> <!-- 排除内部传递的低版本日志框架以避免日志冲突 --> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency>
依赖冲突
冲突成因
当不同依赖链路引入了同一构件的不同版本时(例如链路 A 引入 lib-core:1.0,链路 B 引入 lib-core:2.0),Maven 必须在依赖树中仲裁出一个最终生效版本。如果选用了不兼容的版本,可能在运行时引发 NoSuchMethodError 或 ClassNotFoundException。
仲裁规则
Maven 内部遵循两套严格的仲裁优先级原则:
短路径优先原则(Path Depth):
在依赖树中,距离当前工程路径层级较浅的版本优先入选。
- 链路一:
Project -> Service-A -> Core(1.0)(路径长度为 2) - 链路二:
Project -> Service-B -> Common -> Core(2.0)(路径长度为 3) - 最终生效:
Core:1.0
- 链路一:
先声明优先原则(First-Declared):
当多条链路的依赖路径深度完全相同时,优先采用在当前项目
pom.xml中排在前面的依赖分支。- 链路一:
Project -> Module-A -> Core(1.0)(路径长度为 2) - 链路二:
Project -> Module-B -> Core(2.0)(路径长度为 2) - 若
Module-A在 XML 文件中的声明顺序先于Module-B,则最终生效:Core:1.0
- 链路一:
进阶治理
版本锁定机制
在大型微服务或多模块工程中,为避免各子模块版本分散,父工程使用 <dependencyManagement> 统筹约束依赖版本。
<dependencyManagement>仅负责统一定义版本号和依赖范围规则,本身不会真正下载和引入任何 Jar 包。- 子模块在
<dependencies>中引用相同构件时,无需填写<version>标签,自动继承父模块声明的稳定版本。
BOM 清单导入
使用 BOM(Bill of Materials,物料清单)可以集中管理大型框架生态(如 Spring Boot、Spring Cloud)的全量组件版本,借助 <type>pom</type> 和 <scope>import</scope> 实现配置复用:
<dependencyManagement>
<!-- 导入 Spring Boot 官方 BOM 清单统一锁定版本 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>分析与排查
命令行工具
排查类冲突或冗余依赖时,可利用 Maven 自带的分析插件:
- 查看依赖全貌:
mvn dependency:tree,将整棵解析后的依赖树以缩进格式打印至终端。 - 过滤指定依赖:
mvn dependency:tree -Dincludes=org.slf4j:*,快速定位某个特定类库是由哪些路径间接引入的。 - 分析使用健康度:
mvn dependency:analyze,检测代码中直接使用了但未显式声明的依赖(Used undeclared),以及声明了但代码从未调用的冗余依赖(Unused declared)。
依赖导入报错【

固定打包名【

外部插件引入【

资源打包控制【

构建生命周期
Maven 构建生命周期(Build Lifecycle)是对项目构建过程的高度抽象与标准化,它定义了项目从清理、校验、编译、测试、打包到部署的完整作业顺序。
基础概念
抽象与解耦
构建生命周期本身并不执行具体的编译或打包任务,它只充当流程调度中枢。生命周期由一系列具备先后顺序的构建阶段(Phase)组成。
- 生命周期(Lifecycle):构建流程的集合(例如清理生命周期、默认构建生命周期)。
- 阶段(Phase):生命周期中的某个里程碑节点(例如编译
compile、打包package)。 - 插件目标(Plugin Goal):具体负责干活的功能单元(例如
compiler:compile)。各个阶段通过挂载不同的目标来完成实际的构建动作。

三套周期
Maven 内部维护了三套相互独立、互不干扰的生命周期体系。执行其中一套生命周期的阶段,不会触发另一套生命周期的执行。
clean 周期
负责在构建前清理项目工作区,移除上次构建遗留的中间文件与打包产物,包含三个阶段:
pre-clean:执行清理前的准备工作。clean:清理输出目录(默认删除target文件夹)。post-clean:执行清理后的收尾与日志记录。
default 周期
项目构建的核心生命周期,涵盖从源码处理到最终分发的全过程,包含 23 个阶段。最常用的核心主干阶段如下:
validate:校验项目基础配置与必要依赖是否有效。compile:编译主代码目录下的源码。test:运行单元测试用例。package:将编译生成的字节码归档为可分发格式(如 Jar 或 War)。verify:运行检查程序,验证打包产物的合规性。install:将打包产物安装到本地仓库,供本机其他项目依赖。deploy:将最终产物推送到远程私服仓库,供团队协同使用。
site 周期
负责基于项目的元数据与配置,自动化生成静态站点说明文档,包含四个阶段:
pre-site:执行生成站点文档前的预处理。site:生成项目的 HTML 站点文档。post-site:执行站点收尾与部署准备。site-deploy:将生成的站点发布到远程服务器。
核心阶段
阶段流转
在单套生命周期内部,阶段之间具有严格的前后继承与依赖关系。当在命令行触发某个阶段时,Maven 会自前向后自动依次执行该生命周期中处于该阶段之前的所有阶段。
以执行 mvn package 为例,实际的推进次序如下:
validate:校验元数据规范。generate-sources:处理或自动生成源码。process-sources:解析与过滤主资源文件。compile:完成主程序编译。test-compile:完成测试代码编译。test:执行测试并输出结果报告。package:打包归档生成目标文件。
若直接执行 mvn compile,则打包与测试阶段均不会触发;若执行 mvn install,则会自动先执行完整的编译、测试和打包流程。
阶段组合
若需要跨生命周期协同操作,可以在命令行中按序声明多个阶段参数,Maven 会按顺序依次调度各个生命周期:
mvn clean package上述命令会先调用 clean 生命周期 执行到 clean 阶段(清空 target 目录),随后调用 default 生命周期 执行到 package 阶段(重新编译测试并打包)。
插件绑定
默认绑定机制
Maven 阶段本身仅是一组插槽,为了让开箱即用的构建生效,Maven 会根据工程的 <packaging> 打包类型,将默认插件的目标自动绑定至对应阶段:
| 构建阶段 (Phase) | 默认绑定的插件目标 (Goal) | 实际职责说明 |
|---|---|---|
process-resources | resources:resources | 复制并过滤 src/main/resources 资源 |
compile | compiler:compile | 编译 src/main/java 源码至 target/classes |
test-compile | compiler:testCompile | 编译测试源码至 target/test-classes |
test | surefire:test | 运行测试用例并生成测试报告 |
package(jar) | jar:jar | 将编译后的 classes 归档为 Jar 文件 |
install | install:install | 将产物安装至本地仓库 ~/.m2/repository |
deploy | deploy:deploy | 将构件上传推送至配置的远程仓库 |
自定义阶段绑定
当预设插件无法满足特定需求(如打包时生成源码包、构建时校验代码规范)时,可以在 pom.xml 中将自定义插件目标挂载至特定阶段:
<plugin>
<!-- 将源码打包插件的目标绑定至 verify 阶段 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>当执行 mvn verify 或后续的 install 时,Maven 执行到 verify 阶段便会触发 maven-source-plugin 的 jar-no-fork 目标,额外输出源码包。
进阶调优
阶段跳过与加速
在日常持续集成或紧急发布时,经常需要对特定耗时阶段进行精细控制:
- 跳过测试用例执行:使用
mvn package -DskipTests(测试代码仍会被编译,但不启动运行)。 - 完全跳过测试编译与执行:使用
mvn package -Dmaven.test.skip=true(直接忽略test-compile与test阶段)。 - 多模块并行构建:使用
mvn clean install -T 1C(根据 CPU 核心数启动多线程并行构建相互独立的子模块)。
一一一一一一一一一一一一
坐标与依赖
坐标定位
Maven 通过坐标在仓库中唯一定位任何构件(Artifact)。坐标由三个核心基础维度(GAV)确定:
groupId:组织或公司的唯一标识,通常为倒置的域名。artifactId:具体模块或工程的标识名称。version:当前构件的具体版本号。xml<dependency> <!-- 基础依赖坐标 --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.2.0</version> <!-- 排除传递过来的冲突依赖 --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency>
依赖范围
依赖范围(Scope)用于控制依赖项在编译(Compile)、测试(Test)、运行(Runtime)这三种不同 Classpath 环境下的可见性:
| 依赖范围 (Scope) | 编译 Classpath | 测试 Classpath | 运行 Classpath | 典型场景 |
|---|---|---|---|---|
compile(默认) | 有效 | 有效 | 有效 | 核心业务库,如 spring-core |
provided | 有效 | 有效 | 无效 | 容器已提供的 API,如 servlet-api |
runtime | 无效 | 有效 | 有效 | 仅运行时需要的实现,如 JDBC 驱动 |
test | 无效 | 有效 | 无效 | 单元测试框架,如 junit-jupiter |
system | 有效 | 有效 | 无效 | 本地物理文件引用(需搭配 systemPath) |
依赖传递与冲突
当项目依赖项存在间接依赖时,Maven 会自动向下传递拉取。当多个依赖链路引入了同一构件的不同版本时,遵循两套仲裁规则:
短路径优先:优先采用调用路径最短的依赖。例如
A -> B -> C(1.0)的依赖层级少于A -> D -> E -> C(2.0),最终生效版本为1.0。先声明优先:在依赖深度完全一致时,优先采用在当前
pom.xml中排在前面的依赖声明版本。
仓库体系
仓库分类与检索机制
Maven 构件的存储与查找通过分层仓库拓扑完成:
- 本地仓库:位于本地磁盘(默认
~/.m2/repository),存储项目构建及已拉取的缓存依赖。 - 私服(Nexus / Artifactory):部署在局域网内部的构件服务器,隔离外网并存储内部业务包。
- 中央仓库:由官方维护的公共互联网仓库,收录绝大多数公共开源构件。
构件检索的具体流程如下:
构建进程优先在本地仓库查找目标构件。
若本地未找到,向配置的内网私服或公共镜像节点发起拉取请求。
若私服没有缓存,私服代向外网中央仓库下载并落盘缓存,随后返回给本地仓库。
镜像与私服配置
在全局 settings.xml 中配置公共镜像节点,可以提高网络下载稳定性:
<mirrors>
<!-- 配置中央仓库的公共国内镜像代理 -->
<mirror>
<id>aliyunmaven</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Public Mirror</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>多模块与继承
模块聚合
在复杂微服务或大型系统中,聚合工程(Aggregator)充当所有子模块的统一构建入口。其打包方式必须为 pom,通过 <modules> 组织模块关系:
<project>
<!-- 聚合工程打包类型必须为 pom -->
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>common-utils</module>
<module>order-service</module>
</modules>
</project>属性与继承机制
继承用于集中收敛管理通用配置及依赖版本:
<properties>:定义统一常量与版本号变量。<dependencyManagement>:声明依赖的版本锁定规范。子模块在引入对应依赖时无需显式标注版本号,从而避免团队版本割裂。xml<project> <!-- 父工程锁定全局依赖版本,子模块声明时不带版本号即可继承 --> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.43</version> </dependency> </dependencies> </dependencyManagement> </project>
环境配置与 Profile
多环境配置
Profile 机制允许开发人员根据不同运行环境(开发、测试、生产)定制不同的参数和资源配置:
<profiles>
<!-- 开发环境配置项 -->
<profile>
<id>dev</id>
<properties>
<env.active>dev</env.active>
</properties>
<!-- 默认激活该配置环境 -->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>资源过滤与激活
通过开启资源过滤插件(maven-resources-plugin),Maven 会在构建期将配置文件中的 ${env.active} 占位符解析替换为对应环境的实际属性值。
构建时可以通过命令行参数灵活切换目标配置:
mvn clean package -P dev