跳转至

Maven

Maven 简介

在现代 Java 开发中,随着框架复杂度的提升,依赖管理的规模往往超出了人力可控的范围。Maven 作为一款项目管理和构建工具,其核心价值在于解决两大难题:复杂的依赖管理以及标准化的项目构建。

功能维度 痛点描述 Maven 解决方案
依赖管理 手动导入数百个 Jar 包,版本冲突频发 自动下载、依赖传递、版本冲突自动/手动调节
构建管理 环境不一致导致构建失败,缺乏统一标准 自动化编译、测试、打包、发布,构建过程规范化

Maven 项目构建生命周期

构建是指将源码、资源、依赖转化为可部署应用的过程。Maven 通过生命周期管理,将复杂的步骤简化为简单的命令操作。

命令 描述
mvn clean 清理 target 目录下的编译产物
mvn compile 执行编译过程
mvn test 运行单元测试
mvn package 打包(生成 jar 或 war)
mvn install 将构建结果安装至本地仓库
mvn deploy 将构建结果上传至远程私服

Maven 工程结构与 GAVP 标识

Maven 工程通过 GAVP 属性进行唯一标识,这构成了 Maven 坐标系统的基础。

GroupId: 组织/公司标识(例如 sun),通常按域名倒序排列。

ArtifactId: 项目/模块名称(例如 order-service)。

Version: 版本号,遵循 主版本.次版本.修订号 规则(如 1.0.0)。

Packaging: 打包方式。jar 为默认 Java 项目;war 为 Web 项目;pom 专用于父工程,用于聚合或继承。

Maven 依赖管理深度解析

通过 scope 标签控制 Jar 包在不同阶段的可用性,是管理项目 classpath 的关键。

范围 编译阶段 测试阶段 运行阶段 典型应用
compile 是 是 是 Spring Core, log4j
test 否 是 否 JUnit
provided 是 是 否 Servlet API (容器提供)
runtime 否 是 是 JDBC 驱动

Maven 依赖下载失败

当 Maven 无法正常下载依赖时,不要陷入恐慌,通常只需遵循“排查原因 -> 针对修复 -> 强制清理”的路径即可解决。

下载失败原因

(1)网络与服务端:网络不稳定、服务器宕机或仓库镜像无法连接。

(2)配置与定义:pom.xml 中 GAV(GroupId, ArtifactId, Version)定义错误或版本不存在。

(3)本地环境污染:本地仓库缓存损坏,或存在残留的 lastUpdated 文件阻碍了后续的重新下载。(主要是这个原因)

解决方案

(1)检查网络连接和 Maven 仓库服务器状态。

(2)确保依赖项的版本号与项目对应的版本号匹配,并检查 POM 文件中的依赖项是否正确。

(3)清除本地 Maven 仓库缓存(lastUpdated 文件),因为只要存在lastupdated缓存文件,刷新也不会重新下载。本地仓库中,根据依赖的gav属性依次向下查找文件夹,最终删除内部的文件,刷新重新下载即可!

清除 lastupdated 文件脚本

cls 
   @ECHO OFF 
   SET CLEAR_PATH=D: 
   SET CLEAR_DIR=D:\maven-repository(本地仓库路径)
   color 0a 
   TITLE ClearLastUpdated For Windows 
   GOTO MENU 
   :MENU 
   CLS
   ECHO. 
   ECHO. * * * *  ClearLastUpdated For Windows  * * * * 
   ECHO. * * 
   ECHO. * 1 清理*.lastUpdated * 
   ECHO. * * 
   ECHO. * 2 查看*.lastUpdated * 
   ECHO. * * 
   ECHO. * 3 退 出 * 
   ECHO. * * 
   ECHO. * * * * * * * * * * * * * * * * * * * * * * * * 
   ECHO. 
   ECHO.请输入选择项目的序号: 
   set /p ID= 
   IF "%id%"=="1" GOTO cmd1 
   IF "%id%"=="2" GOTO cmd2 
   IF "%id%"=="3" EXIT 
   PAUSE 
   :cmd1 
   ECHO. 开始清理
   %CLEAR_PATH%
   cd %CLEAR_DIR%
   for /r %%i in (*.lastUpdated) do del %%i
   ECHO.OK 
   PAUSE 
   GOTO MENU 
   :cmd2 
   ECHO. 查看*.lastUpdated文件
   %CLEAR_PATH%
   cd %CLEAR_DIR%
   for /r %%i in (*.lastUpdated) do echo %%i
   ECHO.OK 
   PAUSE 
   GOTO MENU 

Maven 依赖传递

Maven 具有极强的“传染性”。当我们项目 A 依赖项目 B,而 B 又依赖项目 C 时,Maven 会自动将 C 引入到 A 中,这就是依赖传递。

依赖的边界规则

依赖并非无条件传递,它取决于依赖范围(Scope)的设置:

依赖范围 (Scope) 是否传递 说明
compile 是 默认值,全阶段可用,会传递给下游
test / provided 否 仅在特定环境生效,不会传递,下游若需要需手动配置
optional 否 若在依赖中配置 <optional>true</optional>,则主动切断传递链

依赖冲突管理

当一个项目中因传递依赖引入了同一个 Jar 包的多个不同版本时,就会发生依赖冲突。Maven 提供了一套成熟的“仲裁机制”来解决这一问题。

自动选择规则(Maven 仲裁)

当出现冲突时,Maven 遵循以下优先级(按顺序执行):

原则一:短路优先(Shortest Path First)

路径越短的依赖版本越优先。例如 A -> B -> C (v1.0) 和 A -> D -> E -> C (v2.0),Maven 会选择 v1.0。

原则二:先声明优先(First Declaration First)

如果路径长度一致,则在 pom.xml 中先书写的依赖版本优先被选中。

人工介入:手动排除 (Exclusions)

如果 Maven 自动仲裁的版本不符合业务需求(例如自动选择了旧版本导致功能缺失),我们可以强制排除特定的传递依赖。

<dependency>
  <groupId>com.atguigu.maven</groupId>
  <artifactId>pro01-maven-java</artifactId>
  <version>1.0-SNAPSHOT</version>
  <exclusions>
    <exclusion>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Maven 继承

继承是指子工程通过 <parent> 标签,从父工程中继承配置信息。它是实现依赖管理版本统一的核心手段。

父工程:必须设置 <packaging>pom</packaging>,并使用 <dependencyManagement> 标签锁定依赖版本。

子工程:使用 <parent> 指定父坐标。引用依赖时可以省略版本号,直接由父工程决定。

Maven 聚合

聚合是将多个松散的子工程组织在一起,通过父工程进行统一的构建和发布。

父工程通过 <modules> 标签列出所有需要管理的子模块。当对父工程执行构建命令(如 mvn clean install)时,Maven 会根据依赖关系自动计算构建顺序(即“反应堆 Reactor”)并一次性完成所有模块的构建。

Maven 私服

私服(Repository Manager)作为企业内部的 Maven 仓库,主要用于代理外部远程仓库及存储内部私有构件。

当项目请求依赖时,顺序为:本地仓库 -> 私服仓库 -> 远程仓库(中央仓库)。