聊聊Maven的依赖传递、依赖管理、依赖作用域

news2024/11/17 1:27:14

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.coloradmin.cn/o/1084184.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

qt5.14.2+VS源码调试记录

在对qt使用时&#xff0c;有时需要对源代码进行调试&#xff0c;方便进行问题定位和debug&#xff0c;但直接安装的qt不能进入qt源码&#xff0c;需要进行一定的操作才能进行源码调试和定位。 源码调试需要对应版本的pdb文件&#xff0c;可以在官网下载&#xff0c;也可找其它…

Linux文件特殊权限与特殊属性

Linux特殊权限 一、粘滞位权限: 功能: 为目录添加粘滞位后该目录中创建的文件和目录只有创建者和超级管理员可以删除。使用场景: 粘滞位权限用于公共目录和临时目录等场景,它提供了一种限制删除和重命名操作的机制,以保护文件的安全性和完整性示例: passwd 程序,允许普…

ESP32-S3上手开发

1、搭建开发环境 首先搭建开发环境&#xff0c;这里采用了windows下集成开发环境ide进行开发&#xff0c;具体的安装方法&#xff1a;ESP-IDF安装配置 这里使用的乐鑫的esp32s3&#xff0c;N16R8 2、esp32s3模块 从上面图中可以看到&#xff0c;N16R8这里使用了外扩16M的fl…

CustomShapes/自定义形状, CustomCurves/自定义曲线, AnimateableData/数据变化动画 的使用

1. CustomShapes 自定义形状视图 1.1 资源图文件 therock.png 1.2 创建自定义形状视图 CustomShapesBootcamp.swift import SwiftUI/// 三角形 struct Triangle: Shape{func path(in rect: CGRect) -> Path {Path { path inpath.move(to: CGPoint(x: rect.midX, y: rect.mi…

Element UI怎么安装呢?

安装 :::warning 注意 后续演示将会在 Vue CLI 搭建的 Vue 项目上进行操作。如需要请查看 Vue CLI 安装 ::: 通过 YARN 命令安装 $ yarn add element-ui完整引入 代表一次性引入所有组件&#xff0c;比较省心省事&#xff0c;但是项目的打包体积也会跟着变大。 // main.js…

python flask接口字段存在性校验函数(http接口字段校验)(返回提示缺少的字段信息)validate_fields()

文章目录 字段存在性校验示例 字段存在性校验 from flask import Flask, request, jsonifyapp Flask(__name__)def validate_fields(data, fields):missing_fields [field for field in fields if field not in data]if missing_fields:return False, f"缺少以下字段: …

c++多态的使用

为什么要使用多态 项目需求&#xff1a; 因为各种不确定原因&#xff0c;包括人为原因&#xff0c;ODU设备会自动的切换到其它类型的设备&#xff0c;而切换后的设备&#xff0c;和原设备有很多不同的地方。如何完美的实现这个切换呢&#xff1f; 解决方案&#xff1a; 使用…

python opencv 深度学习 指纹识别算法实现 计算机竞赛

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python opencv 深度学习 指纹识别算法实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;4分创新点&#xff1a;4分 该项目较为新颖…

【数据库系统概论】第二章关系数据库

2.1关系数据结构及其形式化定义 前面说过&#xff0c;数据模型由以下三部分构成 数据结构数据操作数据的完整性约束条件 而如今最为重要的数据模型便是关系模型。本书所学的关系数据库就是支持关系模型的数据库系统&#xff0c;因此本章重点研究的也是以下三个部分 一&…

unity发布微信小游戏,未找到 game.json报错原因

unity发布微信小游戏&#xff0c;未找到 game.json报错原因 同一个问题相隔一年遇到两次&#xff0c;两次原因都不一样&#xff0c;记录一下&#xff0c;以后不要再掉坑里 原因一&#xff1a;申请的appID是小程序不是小游戏 解决方法&#xff1a;需要在程序平台修改服务类目 如…

外发文件怎么保存

文件外发是企业日常业务中常见的场景&#xff0c;外发整个流程涉及外发的渠道、外发文件的大小、外发的效率、外发的合规性、文件的保存和管理等一系列的过程。外发文件的保存可以从两个角度着手&#xff1a; 一、接收方 接收方首先要对接收到的文件进行分级和分类&#xff0…

第P9周-YOLOv5Backbone模块

CSP Bottleneck块和C3 类的设计使其非常适合目标检测任务&#xff0c;充分考虑了多尺度特征融合、梯度流动和计算效率等因素。C3 类以及CSP&#xff08;Cross Stage Partial&#xff09; Bottleneck块作为YOLOv5中的一部分&#xff0c;具有以下优势&#xff0c;相对于传统的普通…

京东商品品牌数据采集接口,京东商品详情数据接口,京东API接口

采集京东商品品牌数据的方法如下&#xff1a; 打开网页。在首页【输入框】中输入目标网址批量输入多个关键词并搜索。创建【循环列表】&#xff0c;采集所有商品列表中的数据。编辑字段。创建【循环翻页】&#xff0c;采集多页数据。设置滚动和修改【循环翻页】XPath。启动采集…

日常开发中的图片处理系列工具

一键保存谷歌浏览器当前网页的图片和视频等的插件。 视频图片音乐下载助手_3.1.3_chrome扩展插件下载_极简插件 可高效实现下载管理&#xff0c;网页图片&#xff0c;视频&#xff0c;音频等内容的嗅探和下载&#xff0c;同时扩展集成多个网站的智能脚本&#xff0c;快速提取你…

1600*C. Hamburgers(二分贪心)

Problem - 371C - Codeforces 解析&#xff1a; 二分答案&#xff0c;每次check当前能做的蛋糕数量&#xff0c;判断剩余材料和金钱能否做出来。 注意check中的乘积可能会爆long long&#xff0c;所以二分右边界需要设置1e14以内&#xff08;因为可能会乘一个10000&#xff09;…

element-plus el-cascader 级联组件清空所选数据方法

话不多说直接上代码 import {ref, Ref, reactive} from vue; const cascaderOrg:Ref ref<any>(null) //获取级联组件的ref ref名称即cascaderOrg cascaderOrg.value.cascaderPanelRef.clearCheckedNodes(); //清空所选数据借用官方文档展示该方法 相关细节描述及全…

3.简单场景构建

在新建的项目中&#xff0c;默认存在 Main Camera 和 Directional Light两个对象。若是缺失&#xff0c;可通过选择菜单中的 Game Object->Camera 和 Geme Object->Light->Directional Light进行创建。 1.添加地形及底图 通过在Cesium面板中选择 Cesium World Terrai…

redis如何实现缓存预热

在业务系统中&#xff0c;我们需要在程序启动的时候加载一些常用的数据到内存数据库中&#xff0c;从而减少业务数据库的压力。这就是我们常提到的缓存预热。官方一点的解释是这样的&#xff1a; 缓存预热是一种在程序启动或缓存失效之后&#xff0c;主动将热点数据加载到缓存中…

使用注解新开事务 @Transactional

使用注解新开事务 Transactional(propagation Propagation.REQUIRES_NEW)

QSS样式表的使用

QSS样式表的使用 Chapter1 【Qt】样式表的使用——设置样式的方法一、简述二、开始总结1、先谈谈我们设置样式有几种方法2、再谈谈这几种设置样式方法的优缺点 个人建议 Chapter2 Qt样式表总结Chapter3 【QT】史上最全最详细的QSS样式表用法及用例说明Chapter4 Qt样式表使用总结…