一文彻底搞懂 Maven 依赖——从 <dependency> 到依赖冲突,带你看懂 Maven 的“江湖规矩”

2025-12-04 0 762

一、前言:为什么要研究依赖

写 Java 项目,谁没被 Maven “支配”过呢?

你加了个 Spring Boot Starter,结果一堆库跟着进来;
别人告诉你“scope 写错了”;
编译正常但运行报错,或者 jar 包体积暴涨到 200MB。

这一切背后,其实都是 Maven 依赖系统 在发挥作用。

要真正掌握 Maven,就得先搞清楚:


二、依赖的本质:三段坐标

Maven 的核心设计哲学之一是“声明式依赖”。
你不需要手动下载 jar,只要写出三个坐标:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.3.2</version>
</dependency>

这三个坐标就像一个图书馆的“索书号”:

  • groupId:组织名(相当于出版社)
  • artifactId:模块名(相当于书名)
  • version:版本号(相当于第几版)
元素 含义
组织或公司标识
模块名称
版本号
依赖作用范围(compile、provided、runtime…)
是否为可选依赖
排除指定传递依赖

三、Maven 的依赖来源

Maven 在解析依赖时,会按照以下顺序查找 jar 包:

  1. 本地仓库~/.m2/repository
    → 最近一次构建下载过的包会被缓存到这里。
  2. 远程中央仓库https://repo.maven.apache.org/maven2/
    → Maven 官方中央仓库。
  3. 私有仓库(公司 Nexus / Artifactory)
    → 企业内部维护的依赖镜像。

Maven 会自动从上往下找,找不到就报错:


四、依赖范围(Scope)详解

Scope 是 Maven 的依赖生命周期规则,定义了依赖在哪些阶段可用、是否参与打包、是否传递。

Scope 编译时可见 测试时可见 运行时可见 打包带上 可传递 典型场景
compile 默认值,大多数库
provided 容器已提供(Servlet、Lombok)
runtime JDBC Driver、Logback
test JUnit、Mockito
system 手动指定 jar
import 仅用于依赖管理

五、每种 Scope 的典型示例

1️⃣ compile —— 默认的依赖方式

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version>
</dependency>

特点:

  • 编译、运行、测试全阶段可用;
  • 可传递;
  • 打包会带上。

适合:核心依赖(比如 Spring Context、Apache Commons)。


2️⃣ provided —— 编译要用,运行别带

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

适合:由容器(Tomcat、Jetty)或环境提供的类库。
打包带上会冲突。


3️⃣ runtime —— 运行时才需要的依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>9.1.0</version>
    <scope>runtime</scope>
</dependency>

特点:

  • 编译不需要(用接口即可);
  • 运行时才加载;
  • 打包会带上。

适合:数据库驱动、日志实现等。


4️⃣ test —— 仅在测试阶段使用

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.11.0</version>
    <scope>test</scope>
</dependency>

不会参与最终打包,测试用完即止。


5️⃣ system —— 手动指定路径

<dependency>
    <groupId>com.company</groupId>
    <artifactId>internal-lib</artifactId>
    <version>1.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/lib/internal-lib.jar</systemPath>
</dependency>

️ 注意:

  • 不推荐使用;
  • 不可传递;
  • 会破坏构建的可移植性。

6️⃣ import —— 依赖版本管理用

用于在 dependencyManagement 中引入 BOM(Bill of Materials)

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>3.3.2</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

它不会引入依赖本身,只是导入一组“版本约定”。


六、依赖传递机制:Maven 的“层层借书”

假设:

  • A → 依赖 B
  • B → 依赖 C

则 A 间接依赖了 C(称为传递依赖)。

Maven 的传递规则如下:

A 的 Scope B 的 Scope C 是否传递 说明
compile compile 默认传递
compile provided 不传递
provided compile 不传递
test 任意 不传递
runtime compile/runtime 传递

简单理解:


️ 七、依赖冲突与解决策略

当两个不同版本的相同依赖出现时:

  • 最近路径优先(Nearest Definition Wins)
    → Maven 会选择依赖树中路径最短的版本。

例:

ABcommons-lang3:3.12.0  
ACcommons-lang3:3.14.0

A 直接依赖 C 的路径更短,则取 3.14.0。

如果两者路径一样长:

  • 则选择 声明顺序靠前 的依赖。

查看依赖树命令:

mvn dependency:tree

可查看传递依赖及冲突来源。


强制指定版本:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.14.0</version>
    </dependency>
  </dependencies>
</dependencyManagement>

dependencyManagement 只定义版本,不自动引入依赖。


八、依赖排除(Exclusion)

有时候我们不想要某个传递依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

比如:自己要用 Undertow 或 Jetty,而不想要 Tomcat。


九、最佳实践总结

场景 Scope 建议 原因
普通库依赖 compile 默认
容器内置库(Servlet、JSP) provided 环境已提供
运行时驱动(JDBC、日志实现) runtime 只运行时用
测试框架 test 不参与打包
编译工具(Lombok、MapStruct) provided 编译期生效
公司内部 jar system(慎用) 构建可移植性差
统一管理版本 import(BOM) 方便升级维护

记忆口诀:

像玩 RPG 游戏一样,你给每个依赖分配“职业技能”,
打包、传递、运行都明明白白,不再踩坑!

十、 —— 控制“依赖传递”的另一种方式

现在我们聊聊另一个常被忽略的兄弟:

用于告诉 Maven:

例子:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>2.0.9</version>
    <optional>true</optional>
</dependency>

这意味着:

  • 当前模块能用 slf4j-simple
  • 但依赖此模块的下游项目不会自动拿到它;
  • 如果想用,必须手动声明。

使用场景

场景 是否适合
SDK、框架模块 非常推荐
Spring Boot Starter 常用
应用层 ️ 一般不用
工具类库 不推荐

optional vs provided

特征 true provided
控制对象 依赖传递 生命周期
编译期可见
运行期可见 (环境提供)
传递性 不传递 不传递
场景 模块设计、SDK Web 环境、容器依赖

通俗地说:

  • scope 决定“何时使用”;
  • optional 决定“要不要传下去”。

十一、依赖冲突与解决规则

Maven 在面对同一个依赖的多个版本时,遵循两条核心规则:

  1. 最近路径优先(Nearest Definition Wins)
    —— 谁离当前模块更近,用谁。
  2. 先声明优先(First Declaration Wins)
    —— 同层级冲突时,谁先写谁赢。

可通过以下命令查看依赖树:

mvn dependency:tree

十二、全景图:Maven 依赖生命周期与传递机制(附图)

cc.png


十四、总结与金句彩蛋

元素 控制内容 核心作用
生命周期 控制在哪些阶段可见
传递性 决定是否下游继承
精准排除 清理依赖树

一句话记忆


尾声:让依赖管理优雅如诗

每次写 ,都像在雕琢项目的骨架。
当你真正理解 scopeoptional 与传递关系的微妙平衡,
你就离“构建大师”更近一步了。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 开发教程 一文彻底搞懂 Maven 依赖——从 <dependency> 到依赖冲突,带你看懂 Maven 的“江湖规矩” https://www.zuozi.net/3635.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务