聊聊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 ...
随机推荐
- 【智能安防】基于AI的智能家居安全系统设计与实现
目录 智能家居安全系统设计与实现:AI技术的应用 摘要 随着智能家居市场的快速发展,安全问题也日益突出.本文将介绍基于AI的智能家居安全系统设计与实现技术,重点阐述相关概念.实现步骤和优化改进.通过实 ...
- 推荐一款.NET开源跨平台的开箱即用的DNS服务器软件
前言 今天要给大家推荐一款.NET开源跨平台的开箱即用的DNS服务器软件(用于提供 DNS 解析服务):Technitium DNS Server. 项目介绍 Technitium DNS Serve ...
- 【git】基于JGit通过ssh-url拉取指定commit-id的代码
实现 1️⃣ pom依赖: <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>o ...
- 前端uni-app自定义精美全端复制文本插件,支持全端文本复制插件 可设置复制按钮颜色
随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身. 通过组件化开发,可以有 ...
- 十分钟学会angular
首先笔者有一定的vue基础,但是遇到了含有angular的应用,因此需要学习angular的应用,在学习过程中将自己的学习步骤给一一记录下来,因此假设读者也是具有html及js的基础,在此基础上可以跟 ...
- ARM Trusted Firmware——编译选项(二)
@ 目录 1. 常用部分 2. 安全相关 2.1 签名 2.2 加密 2.3 哈希 2.4 中断 3.GICv3驱动程序选项 4. 调试选项 1. 常用部分 编译选项 解释 BL2 指定生成fip文件 ...
- Nginx配置网站默认https
Nginx配置网站默认https 一.安装Nginx yum install nginx -y 二.修改nginx.conf vim /etc/nginx/nginx.conf 配置80转443 配置 ...
- QPushButton中常用的方法
常用方法如下所示: setCheckable():设置按钮是否已经被选中,如果设置为True,则表示按钮将保持已点击和释放状态. toggl():在按钮之间进行切换 setIcon():设置按钮上的图 ...
- 您在 /var/spool/mail/root 中有新邮件
查看邮件 删除邮件 禁止系统启动邮件检查这样就再有邮件提示了 mail cat /dev/null > /var/spool/mail/root echo "unset MAILCHE ...
- Spring Boot 最佳实践
本文翻译自国外论坛 medium,原文地址:https://medium.com/@raviyasas/spring-boot-best-practices-for-developers-3f3bdf ...
