沉梦手记 沉梦手记
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • 网络通信
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 音视频处理
  • Linux 与容器化运维
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Axios入门
  • Vue Router入门
  • Pinia入门
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)

沉梦听雨

时间是最好的浸渍剂,而沉淀是最好的提纯器🚀
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • 网络通信
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 音视频处理
  • Linux 与容器化运维
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Axios入门
  • Vue Router入门
  • Pinia入门
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)
  • 开发工具篇

    • idea相关

    • 玩转Git

    • Maven相关

      • Maven简介
      • Maven常用命令
      • Maven依赖管理
        • 依赖配置
          • 基本配置格式
          • 核心配置项
        • 依赖传递
          • 依赖的传递性
          • 依赖传递冲突问题
          • 可选依赖
          • 使用场景
          • 配置方式
          • 效果
          • 排除依赖
        • 依赖范围
          • 依赖范围一览表
          • 各依赖范围详解
          • compile(默认)
          • provided
          • runtime
          • test
          • system
          • import
          • 依赖范围的传递性
          • 配置示例
        • 依赖管理(dependencyManagement)
          • 为什么 <dependencyManagement> 不会直接将依赖引入 classpath?
          • 1. 集中管理和声明
          • 2. 避免重复和冲突
          • 3. 灵活性和控制
          • 4. 性能优化
          • 5. 示例说明
          • 总结
        • 学习参考
      • Maven生命周期与插件
      • Maven项目管理工具
      • Maven配置文件详解
    • 前端工具

    • 测试工具

    • AI工具

  • 工具库篇

  • 开发技巧篇

  • 工具类系列

  • 随笔

  • 开发日常
  • 开发工具篇
  • Maven相关
沉梦听雨
2024-09-07
目录

Maven依赖管理

# Maven依赖管理

# 依赖配置

依赖是指当前项目运行所需的 jar 包或其他资源。一个项目可以在 pom.xml 的 <dependencies> 标签中配置多个依赖。

# 基本配置格式

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.29</version>
        <scope>compile</scope>
    </dependency>
</dependencies>
1
2
3
4
5
6
7
8

# 核心配置项

标签 说明 是否必填
groupId 依赖的组织 ID 是
artifactId 依赖的项目 ID 是
version 依赖的版本号 是
scope 依赖的作用范围 否
optional 是否为可选依赖 否
exclusions 排除传递依赖 否
type 依赖类型,默认为 jar 否
classifier 依赖的分类器(如 sources、javadoc) 否

# 依赖传递

# 依赖的传递性

Maven 的依赖关系具有传递性,分为两种:

  1. 直接依赖:在当前项目的 pom.xml 中通过 <dependency> 直接配置的依赖关系。
  2. 间接依赖(传递依赖):直接依赖所依赖的其他资源,会自动传递到当前项目中。
项目 A → 依赖 B(直接依赖)
项目 B → 依赖 C(直接依赖)
则:项目 A → 依赖 C(间接依赖)
1
2
3

# 依赖传递冲突问题

当项目中出现同一资源的不同版本时,Maven 按以下原则解决冲突:

原则 说明
路径优先 当依赖中出现相同资源时,层级越深,优先级越低;层级越浅,优先级越高
声明优先 当资源在相同层级被依赖时,pom.xml 中配置顺序靠前的覆盖配置顺序靠后的
特殊优先 当同级配置了相同资源的不同版本时,后配置的覆盖先配置的

# 可选依赖

可选依赖(Optional Dependency)用于指示某些依赖项不对外传递。

# 使用场景

  • 当你的项目依赖于一个库,但只有在某些特定条件下才会使用它。
  • 当你想对外隐藏某个依赖,不让下游项目自动继承。

# 配置方式

在 pom.xml 中使用 <optional>true</optional> 标签来定义可选依赖:

<dependencies>
    <!-- 必需的依赖项 -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>core-lib</artifactId>
        <version>1.0.0</version>
    </dependency>

    <!-- 可选的依赖项 -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>optional-lib</artifactId>
        <version>2.0.0</version>
        <!-- true 表示对外隐藏,不传递给下游项目 -->
        <optional>true</optional>
    </dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 效果

  • Maven 在构建过程中不会自动将可选依赖传递给依赖该项目的其他项目。
  • 可选依赖仅在当前项目中可用。
  • 如果下游项目也需要该依赖,必须显式声明。

# 排除依赖

排除依赖用于主动断开某个传递依赖,被排除的资源无需指定版本号。

<dependency>
    <groupId>com.example</groupId>
    <artifactId>project-a</artifactId>
    <version>1.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.example</groupId>
            <artifactId>unwanted-lib</artifactId>
            <!-- 注意:exclusion 中不需要指定 version -->
        </exclusion>
    </exclusions>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12

# 依赖范围

依赖的 jar 包默认可以在任何地方使用,可以通过 <scope> 标签设定其作用范围。

# 依赖范围一览表

依赖范围 编译 测试 运行 打包 说明
compile ✅ ✅ ✅ ✅ 默认范围,适用于所有阶段
provided ✅ ✅ ❌ ❌ 编译和测试需要,运行时由 JDK 或容器提供(如 Servlet API)
runtime ❌ ✅ ✅ ✅ 运行和测试需要,编译时不需要(如 JDBC 驱动)
test ❌ ✅ ❌ ❌ 仅测试阶段需要(如 JUnit)
system ✅ ✅ ❌ ❌ 类似 provided,但需通过 <systemPath> 指定本地路径,不推荐使用
import - - - - 仅用于 <dependencyManagement> 中导入 BOM 的依赖管理

# 各依赖范围详解

# compile(默认)

编译依赖是默认范围,适用于所有阶段(编译、测试、运行)。如果不指定 <scope>,则使用 compile 范围。

# provided

提供的依赖范围,表示这些依赖在编译和测试阶段是必需的,但在运行时由 JDK 或运行环境(如 Java EE 容器)提供,因此不会被打包到最终产物中。

典型场景:javax.servlet-api 在编译时需要,但运行时由 Tomcat 等 Web 容器提供。

# runtime

运行时依赖范围,表示这些依赖在运行和测试阶段是必需的,但在编译阶段不需要。这些依赖会被打包到最终产物中。

典型场景:JDBC 驱动在编译时只需要接口,运行时才需要具体的驱动实现。

# test

测试依赖范围,仅在测试阶段有效,不会被打包到最终产物中。

典型场景:JUnit、Mockito 等测试框架。

# system

系统依赖范围,与 provided 类似,但必须通过 <systemPath> 标签指定依赖的本地路径,而不是从 Maven 仓库获取。不推荐使用,因为会降低项目的可移植性。

# import

导入依赖范围,仅用于 <dependencyManagement> 中,用于导入 BOM(Bill of Materials)中定义的依赖版本管理。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.7.18</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
1
2
3
4
5
6
7
8
9
10
11

# 依赖范围的传递性

依赖范围会影响传递依赖的范围,规则如下:

直接依赖 \ 间接依赖 compile provided runtime test
compile compile - runtime -
runtime runtime - runtime -
provided provided - provided -
test - - - -

说明:provided 和 test 范围的依赖不会传递。

# 配置示例

<dependencies>
    <!-- 编译依赖(默认) -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>compile-dep</artifactId>
        <version>1.0.0</version>
        <scope>compile</scope>
    </dependency>

    <!-- 已提供依赖 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>

    <!-- 运行时依赖 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
        <scope>runtime</scope>
    </dependency>

    <!-- 测试依赖 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>

    <!-- 系统依赖(不推荐) -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>system-dep</artifactId>
        <version>1.0.0</version>
        <scope>system</scope>
        <systemPath>${project.basedir}/lib/system-dep.jar</systemPath>
    </dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 依赖管理(dependencyManagement)

# 为什么 <dependencyManagement> 不会直接将依赖引入 classpath?

在 Maven 项目中,<dependencyManagement> 元素的主要目的是集中管理依赖的版本、范围和其他配置属性,但不会直接将这些依赖添加到项目的 classpath 中。

# 1. 集中管理和声明

  • 集中管理:<dependencyManagement> 提供了一种方式来集中定义依赖的版本、作用域等信息,确保所有子模块使用一致的依赖配置。
  • 声明而非引入:它只是声明了依赖项及其配置,而不会实际将这些依赖添加到项目的构建路径(classpath)中。这意味着你可以在父 POM 或 BOM 文件中定义大量依赖,而不会因为这些声明导致不必要的依赖被引入。

# 2. 避免重复和冲突

  • 避免重复声明:如果每个子模块都单独声明依赖的版本,容易导致版本不一致或重复声明的问题。通过 <dependencyManagement>,子模块只需要声明依赖的 groupId 和 artifactId,不必指定版本号,减少了冗余配置。
  • 防止冲突:由于依赖版本由父 POM 或 BOM 统一管理,可以有效避免不同子模块之间依赖版本不一致导致的冲突问题。

# 3. 灵活性和控制

  • 按需引入:子模块可以根据需要选择性地引入所需的依赖,而不是被动地继承所有声明的依赖。这使得项目结构更加灵活,允许开发者根据实际情况调整依赖。
  • 覆盖版本:虽然 <dependencyManagement> 定义了默认版本,但子模块仍然可以选择覆盖这些版本,提供了一定的灵活性。

# 4. 性能优化

  • 减少解析时间:Maven 在解析依赖时,只会处理实际引入的依赖,而不是所有声明的依赖。这有助于提高构建性能,尤其是在大型项目中有大量依赖的情况下。

# 5. 示例说明

父 POM 使用 <dependencyManagement> 管理依赖版本:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>2.7.18</version>
        </dependency>
    </dependencies>
</dependencyManagement>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

子模块选择性引入需要的依赖(无需指定版本号):

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!-- 版本号由父 POM 的 dependencyManagement 统一管理 -->
    </dependency>
</dependencies>
1
2
3
4
5
6
7

在这个例子中,spring-boot-starter-web 被引入到了子模块的 classpath 中,而 spring-boot-starter-data-jpa 没有被引入。这样既保持了灵活性,又避免了不必要的依赖加载。

# 总结

<dependencyManagement> 不会直接将依赖引入到项目的 classpath 中,主要是为了实现依赖版本的集中管理,避免重复和冲突,提供灵活性和控制,并优化构建性能。这种方式特别适用于大型多模块项目,能够显著简化依赖管理并提高项目的可维护性。

# 学习参考

  • 依赖机制 – Maven 官方文档 (opens new window)
上次更新: 2026/7/24 16:59:26
Maven常用命令
Maven生命周期与插件

← Maven常用命令 Maven生命周期与插件→

Theme by Vdoing | Copyright © 2023-2026 沉梦听雨 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式