当前位置: 首页 > news >正文

聊聊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-starterspring-boot-starter-jsonspring-boot-starter-tomcatspring-webspring-webmvc

Maven依赖关系如下图所示:

外部库如下图所示:

其中,业务项目对spring-boot-starter-web的依赖称为直接依赖,对spring-boot-starter-web的依赖项:

spring-boot-starterspring-boot-starter-jsonspring-boot-starter-tomcatspring-webspring-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个问题:

  1. Maven是单继承的,一个项目只能有一个parent项目
  2. 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,那么这个依赖不会传递。

http://www.lryc.cn/news/193139.html

相关文章:

  • centos6/7 SOCKS5 堆溢出漏洞修复(RPM方式)curl 8.4 CVE-2023-38545 CVE-2023-38546
  • C#,数值计算——数据建模Proposal的计算方法与源程序
  • 如何使用命令生成动态链接库.dll文件(保姆级教学)
  • Qt之模块介绍
  • Socks5代理和代理IP
  • 计算机指令、机器码
  • MyLife - Docker安装Consul
  • Leetcode刷题笔记--Hot61-70
  • python特别篇—github基本操作手册
  • tiktok直播websocket序列化与反序列化
  • 微信picker弹出之后 , 背景变成灰色是怎么做的
  • 通用考勤后台管理系统
  • LeetCode75——Day5
  • 面向C++模块的开源 IFC SDK
  • Docker开启远程访问+idea配置docker+dockerfile发布java项目
  • 基于nodejs+vue教学辅助管理系统
  • Qt 子线程中无限递归的信号槽导致主线程槽失效的原因和解决办法
  • 实施 DevSecOps 最佳实践
  • 第56节——redux-toolkit中的createAction——了解
  • 【数据结构】排序--选择排序(堆排序)
  • C# 图解教程 第5版 —— 第2章 C# 和 .NET Core
  • 数据结构 | Huffman TreeCode
  • mysql拼接字符串函数
  • python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域
  • 《动手学深度学习 Pytorch版》 8.6 循环神经网络的简洁实现
  • leetcode做题笔记173. 二叉搜索树迭代器
  • RPA流程自动化的优势和好处
  • 搭建 Hadoop 生态集群大数据监控告警平台
  • 课题学习(七)----粘滑运动的动态算法
  • python二次开发CATIA:测量曲线长度