聊聊Maven的依赖传递、依赖管理、依赖作用域
1. 依赖传递
在Maven中,依赖是会传递的,假如在业务项目中引入了spring-boot-starter-web依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.4</version>
</dependency>
那么业务项目不仅直接引入了spring-boot-starter-web依赖,还间接引入了spring-boot-starter-web的依赖项:
spring-boot-starter、spring-boot-starter-json、spring-boot-starter-tomcat、spring-web、spring-webmvc。
Maven依赖关系如下图所示:

外部库如下图所示:

其中,业务项目对spring-boot-starter-web的依赖称为直接依赖,对spring-boot-starter-web的依赖项:
spring-boot-starter、spring-boot-starter-json、spring-boot-starter-tomcat、spring-web、spring-webmvc
的依赖称为间接依赖。

2. 依赖管理
dependencyManagement元素主要用来统一管理依赖项的版本号。
假如父项目的pom文件中声明了如下依赖:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
</dependencies>
</dependencyManagement>
那么子项目在添加该依赖时,可以不指定版本号:
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
</dependencies>
Maven会自动找到父项目中声明的该依赖项的版本号,如下图所示:


这样的优点是可以统一在父项目中管理依赖项的版本号,如果需要升级版本,只需改动父项目一个地方即可,子项目不用改动。
说明:
1)dependencyManagement只是声明依赖项,并没引入依赖项,子项目仍需显式引入,不过可以不指定版本号
2)如果子项目不想使用继承的父项目中的版本号,在子项目中指定版本号即可
3. 依赖作用域
在Maven中,可以使用scope来指定当前依赖项的作用域,常见的值有:compile、provided、runtime、test、import等,如下所示:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
3.1 compile
compile是默认的作用域,如果引入依赖时,没有明确指定作用域,则依赖作用域为compile。
作用域为compile的依赖,在编译、测试和运行时都是可用的,并且会参与项目的打包过程,该依赖会传递给依赖该模块的其他模块。
3.2 provided
作用域为provided的依赖,在编译和测试时是可用的,在运行时是不可用的,不会参与项目的打包过程,也不会传递给其他模块。
比如lombok依赖会在编译时生成相应的get、set等方法,在运行时就不需要这个依赖了,因此常常被指定为provided:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
因为被指定为provided,项目打包时是不包含lombok依赖项的,如下图所示:

如果将上面的代码<scope>provided</scope>删除的话,运行时是下图这样的:

以上验证需将项目打包方式改为war,打包后查看WEB-INF/lib目录
3.3 runtime
作用域为runtime的依赖,在测试和运行时是可用的,在编译时是不可用的,会参与项目的打包过程,也会传递给依赖该模块的
其他模块。
说明:
作用域为runtime的依赖中的类,在项目代码里不能直接用,用了无法通过编译(这里指的是在src/main/java下使用)。
以mysql-connector-java为例,假如引入依赖时是下面这样的:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
下面的示例代码是可以编译通过的:

如果将作用域修改为runtime,上面的示例代码无法通过编译:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
<scope>runtime</scope>
</dependency>

3.4 test
作用域为test的依赖,只在测试时可用(包括测试代码的编译、执行),不会参与项目的打包过程,也不会传递给其他模块。
常见的有junit、mockito等:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
因为被指定为test,项目打包时是不包含junit依赖项的,如下图所示:

如果将上面的代码<scope>test</scope>删除的话,运行时是下图这样的:

以上验证需将项目打包方式改为war,打包后查看WEB-INF/lib目录
说明:
作用域为test的依赖中的类或者注解只能在src/test/java下才可以使用,在src/main/java下无法使用,如junit包下的@Test注解和org.junit.Assert断言类。
3.5 import
每个项目,一般都会继承自一个父项目,在实际的工作中,这个父项目一般都是公司架构组提供的带有公司特色的一个基础项目,
当然也可以是spring boot官方的项目。
以spring boot官方的项目为例:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
</parent>
这个父项目中,会使用dependencyManagement标签对依赖项的版本统一管理,子项目中,可以按需引入父项目
dependencyManagement中定义的依赖,但可以不指定版本号(版本号会自动继承父项目中定义的版本号)。
但是存在以下2个问题:
- Maven是单继承的,一个项目只能有一个parent项目
- parent项目dependencyManagement中的依赖项会越来越多,不好管理
依赖作用域import的出现就是为了解决以上问题,它可以通过非继承的方式批量引入另一个依赖项中
dependencyManagement元素中定义的依赖项,如下所示:
<dependencyManagement>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-bom</artifactId>
<version>${spring-session-bom.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
说明:<scope>import</scope>只能用在dependencyManagement下type为pom的dependency中。
以上代码等价于添加了以下6个依赖项:

可以看出,使用<scope>import</scope>可以模块化的管理依赖项,提高复用性,pom文件也更加简洁。
3.6 区别
综上所述,各个依赖作用域的区别如下表所示:
| scope取值 | 编译时可用 | 测试时可用 | 运行时可用 | 是否参与打包 | 依赖传递 |
|---|---|---|---|---|---|
| compile | √ | √ | √ | √ | √ |
| provided | √ | √ | × | × | × |
| runtime | × | √ | √ | √ | √ |
| test | × | √ | × | × | × |
4. 影响依赖传递的因素
4.1 依赖作用域(scope)
依赖作用域会影响依赖传递,从上表可以看出,如果scope为provided或者test,该依赖不会传递,只有scope为compile或者runtime,
该依赖才会传递。
4.2 可选依赖(optional)
通过dependency标签引入依赖时,可以通过<optional>指定该依赖是不是可选的,默认值为false:
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.2.3</version>
<optional>true</optional>
</dependency>
如果<optional>值为true,那么这个依赖不会传递。
聊聊Maven的依赖传递、依赖管理、依赖作用域的更多相关文章
- Java开发学习(二十九)----Maven依赖传递、可选依赖、排除依赖解析
现在的项目一般是拆分成一个个独立的模块,当在其他项目中想要使用独立出来的这些模块,只需要在其pom.xml使用<dependency>标签来进行jar包的引入即可. <depende ...
- Maven依赖传递、依赖传递排除、依赖冲突
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6628429.html 一:Maven依赖传递 假如有Maven项目A,项目B依赖A,项目C依赖B.那么我们可 ...
- mavean的依赖传递和排除依赖
三个mavean项目 A .B. C 如果B依赖A(A先执行clean package命令) 那么B得pom.xml文件里面就写 <dependency> <groupId> ...
- maven依赖传递和排除依赖冲突
1 依赖的传递 假如 A项目 依赖 a.jar 1.0.1,b.jar 1.0.1,没有直接依赖c.jar 1.0.1,但是b.jar 1.0.1依赖了c.jar 1.0.1,可以说A项目间接依赖了c ...
- maven的中传递依赖,maven的依赖管理(转)
在maven的pom文件中 <dependencies> <dependency> <groupId>junit</groupId> <artif ...
- POM(project Object Model) Maven包管理依赖 pom.xml文件
什么是POM POM全称为“Project Object Model”,意思是工程对象模型.Maven工程使用pom.xml来指定工程配置信息,和其他文本信息.该配置文件以xml为格式,使用xml语法 ...
- 10.Maven依赖排除 禁止依赖传递 取消依赖的方法
转自:https://www.cnblogs.com/duanxz/p/6084494.html 大家都知道Maven的优点是依赖管理,特别是前期使用ANT的开发者都有很多感触.最近要开发一个java ...
- 说说maven依赖冲突,依赖调解,依赖传递和依赖范围
说maven依赖冲突之前需要先说说maven的 依赖传递. 依赖传递 当前项目引入了一个依赖,该依赖的依赖也会被引入项目.更加准确的说法是,maven会解析直接依赖的POM,将那些必要的间接依赖,以传 ...
- Maven依赖范围及依赖传递
一: 依赖范围scope 共5种,compile (编译).test (测试).runtime (运行时).provided.system 不指定,则依赖范围默认为compile. compile:编 ...
- Maven最佳实践:管理依赖
From:http://juvenshun.iteye.com/blog/337405 Maven最佳实践:管理依赖 "If I have seen further it is by sta ...
随机推荐
- 痞子衡嵌入式:从功耗测试角度了解i.MXRTxxx系列片内SRAM分区电源控制
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是从功耗测试角度了解i.MXRTxxx系列片内SRAM分区电源控制. 我们知道配合 MCU 一起工作的存储器包含 ROM(Flash) 和 ...
- VSCode 编辑器的基本配置
VSCode 编辑器的基本配置 在正式开始本文的内容之前,请允许我先做一些自我介绍: 严格来说,我是个自由职业者,经常会参与一些计算机专著的写作与翻译工作(主要作品如下图所示),业余偶尔也会有一些机会 ...
- 【HDC.Cloud 2023】华为云区块链分论坛内容值得再读!
摘要:在Web3时代,基础设施不仅仅是传统意义上的服务器.网络等,还包括了区块链节点.智能合约等,这些基础设施的稳定性和可信度直接影响着Web3的发展. 本文分享自华为云社区<[HDC.Clou ...
- 利用Spire.Pdf实现PDF添加印章的操作
在一些文档处理中,我们需要对PDF盖上公司的印章操作,本篇随笔介绍利用Spire.Pdf实现PDF添加印章的操作,如全章和骑缝章的处理. 1.实现效果和处理代码 有时候,需要在特定的位置盖章,以及各个 ...
- ch-manager.sh
[root@dev-clickhouse1 ~]# cat ch-manager.sh #!/bin/bash ch_arr=(ch1-shard1-main ch1-shard2-sub ch2-s ...
- 【技术实战】Vue技术实战【五】
需求实战一 效果展示 代码展示 <template> <div class="home-component"> <div class="pr ...
- Angular: 点击一次按钮,增加一个元素
解决方案 思路 在组件的typesscript文件中,创建一个数组来存储每个按钮的信息 在模板中使用 *ngFor 指令来循环渲染按钮列表 在按钮事件的处理函数中,每次点击按钮时向按钮数组添加一个新的 ...
- UE源码分析:Slate 类鼠标输入处理
序言 UE4.25版本 本章看一下UE的 "类鼠标"输入处理(其实就是鼠标和触摸的输入,我也没找到专门的术语来代指,英文UE用的是PointerXXX),主要是按下.移动.抬起等相 ...
- 王道oj/problem21
网址:oj.lgwenda.problem/21 思路:先序遍历,中序遍历,后序遍历用递归实现:层序遍历用一个链队实现,出队一个元素,顺序入队他的左孩子和右孩子 代码: #define _CRT_SE ...
- python3使用ESL和sipp自动多轮压测FreeSWITCH
环境:CentOS 7.6_x64 FreeSWITCH版本 :1.10.9 sipp版本:3.6.1 python版本:3.9.12 日常工作中,有时会遇到批量自动压测FreeSWITC ...
