Maven 依赖范围与排除

Maven 是一个强大的构建工具,依赖管理是其核心功能之一。在大型项目中,可能会有多个模块和库之间的依赖关系,Maven 通过 依赖范围(Scope) 和 依赖排除(Exclusions) 机制来控制依赖的使用方式,并解决版本冲突的问题。

本篇文章将深入探讨:

  1. Maven 依赖范围(Scope)
  2. 如何排除冲突的依赖(Exclusions)
  3. 实战案例:处理依赖冲突

1. Maven 依赖范围(Scope)

1.1 什么是依赖范围?

依赖范围(Scope)决定了依赖项在 Maven 构建生命周期中的可用性,即它在编译、测试、运行等不同阶段是否生效。

Maven 提供了以下 6 种依赖范围:

范围(Scope) 作用 可用阶段
compile(默认) 适用于所有阶段(编译、测试、运行) compile、test、runtime、package、install、deploy
provided 由 JDK 或容器提供,不会打包到 JAR/WAR compile、test
runtime 编译时不需要,运行时需要 runtime、package、install、deploy
test 仅在测试阶段可用,不会被打包 test
system 本地提供,不从 Maven 仓库下载 compile、test
import 用于导入 BOM(Bill of Materials) 仅用于 dependencyManagement

1.2 依赖范围详解

1. compile(默认)
  • 作用:默认范围,适用于所有构建阶段(编译、测试、运行)。
  • 适用场景:项目需要该依赖进行编译和运行。

示例:

xml 复制代码
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
    <scope>compile</scope>
</dependency>

行为:

  • 编译时可用 ✅
  • 测试时可用 ✅
  • 运行时可用 ✅
  • 参与打包 ✅

2. provided
  • 作用 :类似 compile,但不会打包到最终的 JAR/WAR,因为它由 JDK 或容器(如 Tomcat)提供。
  • 适用场景:如 Servlet API、JDBC API,在 Web 服务器或应用容器中已存在。

示例:

xml 复制代码
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

行为:

  • 编译时可用 ✅
  • 测试时可用 ✅
  • 运行时不可用 ❌
  • 参与打包 ❌

3. runtime
  • 作用:运行时需要,编译时不需要。
  • 适用场景:如 JDBC 驱动,编译时不直接引用,但运行时需要加载。

示例:

xml 复制代码
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.26</version>
    <scope>runtime</scope>
</dependency>

行为:

  • 编译时不可用 ❌
  • 测试时可用 ✅
  • 运行时可用 ✅
  • 参与打包 ✅

4. test
  • 作用:仅在测试阶段可用,不会打包到最终的应用中。
  • 适用场景:如 JUnit、Mockito 等测试框架。

示例:

xml 复制代码
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>

行为:

  • 编译时不可用 ❌
  • 测试时可用 ✅
  • 运行时不可用 ❌
  • 参与打包 ❌

5. system
  • 作用:依赖必须提供本地路径,Maven 不会从远程仓库下载。
  • 适用场景 :使用本地的 JAR(但推荐使用 provided 代替)。

示例:

xml 复制代码
<dependency>
    <groupId>com.example</groupId>
    <artifactId>custom-lib</artifactId>
    <version>1.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/lib/custom-lib.jar</systemPath>
</dependency>

行为:

  • 编译时可用 ✅
  • 测试时可用 ✅
  • 运行时可用 ✅
  • 参与打包 ✅

6. import
  • 作用 :用于 dependencyManagement,引入 BOM(Bill of Materials)。
  • 适用场景:Spring Boot 采用 BOM 机制,管理一组依赖的版本。

示例:

xml 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.5.0</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

2. 依赖排除(Exclusions)

2.1 依赖传递性

如果 A 依赖 B,而 B 依赖 C,则 A 会自动引入 C,这被称为传递性依赖。

xml 复制代码
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.9</version>
</dependency>

spring-web 依赖 commons-logging ,如果项目中已使用 SLF4J ,可能会发生冲突。


2.2 排除依赖

为了避免冲突,可以使用 <exclusions> 排除不需要的传递性依赖。

示例:

xml 复制代码
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.9</version>
    <exclusions>
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3. 实战案例:解决依赖冲突

3.1 查看依赖树

当出现依赖冲突时,可以使用 mvn dependency:tree 查看依赖关系。

bash 复制代码
mvn dependency:tree

示例输出:

plaintext 复制代码
[INFO] com.example:my-app:jar:1.0-SNAPSHOT
[INFO] ├─ org.springframework:spring-core:jar:5.3.9:compile
[INFO] │  ├─ commons-logging:commons-logging:jar:1.2:compile
[INFO] ├─ org.slf4j:slf4j-api:jar:1.7.30:compile

如果 commons-logging 和 slf4j 冲突,可以使用 <exclusions> 解决。


4. 总结

  • Maven 提供 6 种依赖范围:

    • compile(默认):适用于所有阶段
    • provided:编译需要,运行时由容器提供
    • runtime:运行时需要,编译时不需要
    • test:仅测试阶段可用
    • system:本地提供,需手动指定路径
    • import:用于 BOM
  • 可以使用 <exclusions> 解决依赖冲突。

  • 使用 mvn dependency:tree 检查依赖冲突。

掌握 Maven 依赖管理的这些技巧,可以有效提高项目的稳定性和可维护性!🚀

相关推荐
涉密IT资质笔记12 小时前
涉密人员脱密期管理规范:期限分级模型、就业限制边界与违规认定标准
java·服务器·前端·网络·数据库
mmsx12 小时前
Android Dialog 插槽模式:用一套壳统一全应用的弹窗风格
android·java·dialog·开发语言
u01110267513 小时前
工具页案例图如何编写 alt让图片说明与处理场景对应
java·前端·javascript·图像处理·人工智能·算法·ai作画
码上有光13 小时前
Linux:进程间通信——匿名管道通信、命名管道通信
android·java·linux·linux通信·匿名通信·命名通信
落魄实习生13 小时前
Agent Scope Java 2.x 系列【11】AgentState 与状态存储
java·开发语言·ai
Ivanqhz13 小时前
干涉图着色
java·服务器·网络·数据库·人工智能·深度学习
程序鉴定师14 小时前
2026年深圳小程序/App开发公司技术选型指南:从架构设计到交付标准全维度评估
java·小程序·uni-app·php·objective-c
用户0942485680314 小时前
第20章:JVM G1 GC原理、日志与调优实战
java·jvm
打工仔折腾 AI14 小时前
把模型切换交给平台:用蓝耘智能路由搭建商品评论分析工具
java·服务器·前端·后端·python·性能优化·ai agent 实战
后端LV14 小时前
Caffeine 源码详解:为什么它是最快的 Java 本地缓存——一次压测引发的源码考古
java·后端