关山难越,谁悲失路之人;萍水相逢,尽是他乡之客。
百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程教程 > 技术文章 > 正文

Maven的依赖作用域和依赖传递

guanshanw 2023-09-20 10:57 25 浏览 0 评论

在Java项目开发中,Maven是我们最常用的依赖管理和构建工具了!我们常常通过添加dependency节点,就能够很方便地加入依赖,而不需要我们自己去手动下载jar文件并引入。

今天主要是来总结一下在Maven中依赖的作用域和传递。

一、依赖作用域

通过在每个dependency中设定scope字段,即可声明其作用域,例如:

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.28</version>
	<!-- 声明作用域 -->
	<scope>provided</scope>
</dependency>

上面我们就设定了lombok这个依赖的作用域为provided。

常用的作用域字段值及其意义如下:

  • compile:这是默认的scope(即你不写scope字段的话,这个依赖作用域就是compile),表示依赖在编译测试运行时都是可用的,并且会参与项目的打包过程,该依赖会传递给依赖该模块的其他模块
  • provided:表示依赖在编译测试时是可用的,但该依赖不会参与程序运行阶段,即程序运行时无法调用该依赖中的类,它不会参与项目的打包过程,也不会传递给其他模块
  • runtime:表示依赖仅在运行时是可用的,但在编译和测试时不需要,它会传递给依赖该模块的其他模块,但不会参与项目的打包过程
  • test:表示依赖只在测试运行时使用,不会参与项目的打包过程,也不会传递给其他模块

可见一个Maven项目,从编译到运行会经历三个阶段:编译 → 测试 → 运行

不同作用域在三个阶段的可见性如下表:


编译时可用

测试时可用

运行时可用

compile

provided

x

runtime

x

test

x

x

二、作用域和打包

我们常常会使用maven-assembly-plugin插件,让我们在打包的时候将所有的依赖都打包至最后的jar文件中,使得jar文件可以直接运行。

不过真的是所有的依赖都会被打包到最后的jar中吗?

其实并不是,在使用maven-assembly-plugin插件插件时,默认只有scope为compile和runtime的依赖才会被包含在最终的结果中

因此,为了减小最终jar的大小,我们应当将运行时不需要的依赖设置为provided或者test,当然这也是根据用途选择。

例如lombok依赖会在编译的时候生成getter和setter的代码,但是运行的时候这个依赖就不需要了,因此它常常被设定为provided。

但是在Spring Boot开发中就不一样了,Spring Boot工程中,使用的是spring-boot-maven-plugin,这个插件也能完成同样的目的,即打包时将所有的依赖全部打包到一个jar中,但是这个插件会将所有的依赖都打包进去,无论其scope是什么。

不过,我们可以在这个插件中进行配置,声明打包时需要排除的依赖,例如:

<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<configuration>
		<excludes>
			<!-- 打包时排除lombok依赖 -->
			<exclude>
				<groupId>org.projectlombok</groupId>
				<artifactId>lombok</artifactId>
			</exclude>
		</excludes>
	</configuration>
</plugin>

三、依赖的传递

事实上,在Maven中,依赖也是会传递的,我们先创建一个名为first的项目,并引入lombok依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.gitee.swsk33</groupId>
	<artifactId>first</artifactId>
	<version>1.0.0</version>

	<properties>
		<java.version>17</java.version>
		<maven.compiler.source>${java.version}</maven.compiler.source>
		<maven.compiler.target>${java.version}</maven.compiler.target>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<!-- 引入lombok依赖 -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.28</version>
		</dependency>
	</dependencies>
</project>

这是项目first的pom.xml文件,其groupId为com.gitee.swsk33,其artifactId为first,其版本为1.0.0,现在在其工程目录下执行mvn clean install安装至本地仓库使得待会可以引用它。

现在在新建项目second,并引用上述的first作为依赖,如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.gitee.swsk33</groupId>
	<artifactId>second</artifactId>
	<version>1.0.0</version>

	<properties>
		<java.version>17</java.version>
		<maven.compiler.source>${java.version}</maven.compiler.source>
		<maven.compiler.target>${java.version}</maven.compiler.target>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<!-- 引用first项目 -->
		<dependency>
			<groupId>com.gitee.swsk33</groupId>
			<artifactId>first</artifactId>
			<version>1.0.0</version>
		</dependency>
	</dependencies>
</project>

好的,现在展开IDEA左侧栏的外部库部分,看看second项目的依赖:

可见second项目仅仅是引入了first项目,但为什么外部库中包含了lombok依赖呢?这是因为first依赖lombok,而second依赖first时,lombok也被传递给了second。

同样地,如果现在又有一个项目third依赖second呢?那么third也会间接依赖lombok,也可以使用lombok中的类。

当然,依赖并不总是会传递的,有下列因素会影响依赖传递。

scope作用域

scope不仅仅代表这个依赖的作用域,也会影响依赖的传递,只有scope为compile和runtime的依赖是会传递的

假设现在把上述first项目中的lombok依赖scope改成provided或者test,然后重新执行mvn clean install,你就会发现在second的依赖中,就看不到lombok了!

optional字段

除了scope之外,还可以设定依赖的optional字段,当设定为true时代表这个依赖是可选的,那么这时无论其scope是什么,这个依赖都不会传递。默认情况下,即不声明依赖的optional字段时,它的值是false。

现在将first中的lombok依赖的optional字段声明为true:

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.28</version>
	<optional>true</optional>
</dependency>

然后重新mvn clean install,再次打开second项目,你就会发现lombok依赖就没有传递过来了!

所以如果在制作外部库需要其他人引用的时候,我们可以将一些仅仅是外部库需要使用但是其它项目不一定要使用的依赖的optional设定为true,避免其他开发者引入你的外部库时发生依赖冲突。

作:守望时空33
链接:https://juejin.cn/post/723958561085882373

相关推荐

七条简单命令让您玩转Git
七条简单命令让您玩转Git

凭借着出色的协作能力、快速部署效果与代码构建辅助作用,Git已经得到越来越多企业用户的青睐。除了用于开发商业及消费级应用之外,众多科学及政府机构也开始尝试使用这...

2023-10-07 12:14 guanshanw

基本完整的关于Git分支branch的操作
基本完整的关于Git分支branch的操作

Git使用背景项目中要用到dev或者其他分支开发完代码,需要将该分支合并到master的需求操作步骤下面以dev名称为lex为分支名为例来操作一遍客户端操作:...

2023-10-07 12:14 guanshanw

Git 进阶(合并与变基)
Git 进阶(合并与变基)

在Git中整合来自不同分支的修改主要有两种方法:合并(merge)以及变基(rebase)合并(merge)merge流程图merge的原理是找到这两个分...

2023-10-07 12:13 guanshanw

Git学习笔记 003 Git进阶功能 part5 合并(第一部分)

合并(merge)是很常用的操作。尤其是一个庞大的很多人参与开发的企业级应用。一般会设定一个主分支,和多个副分支。在副分支开发完成后,合并到主分支中。始终保持主分支是一个完整的,稳定的最新状态的分支。...

非标题党,三张图帮你理解git merge和git rebase的区别
非标题党,三张图帮你理解git merge和git rebase的区别

初始场景:基于正常的开发分支修改几个小bug,然后在合并到开发分支上。gitmergegitcheckoutfeaturegitmergeho...

2023-10-07 12:13 guanshanw

git 初次使用(01)
git 初次使用(01)

先从github上克隆代码下来:使用vscode克隆代码如下图,填写上github仓库地址:vscode有时候克隆代码速度比较慢,可以用命令行方式克隆gitc...

2023-10-07 12:12 guanshanw

Git 远程操作

4.Git远程操作命令说明gitremote远程版本库操作gitfetch从远程获取版本库gitpull下载远程代码并合并gitpush上传远程代码并合并4.1远程版本库操作gitre...

Git常用命令-总结
Git常用命令-总结

创建git用户$gitconfig--globaluser.name"YourName"$gitconfig--globaluser.em...

2023-10-07 12:12 guanshanw

git中删除从别人clone下来项目的git信息,并修改为自己的分支

如果你从别人的Git存储库中克隆了一个项目,并想要删除与该存储库相关的Git信息,并将其修改为你自己的分支,则可以执行以下步骤:使用gitclone命令克隆存储库:gitclone<u...

git系列-回滚和放弃本地修改

回滚历史提交就是reset的功能。这种情况是已经提交远程仓库,需要回滚到之前的提交。gitreset--hardcommitId//注:强制提交后,当前版本后面的提交版本将会删掉!gi...

GIT使用小技巧大全
GIT使用小技巧大全

在大型软件工程的开发过程中,版本控制是无法绕过去的;目前来说,最火的版本控制软件就是GIT了。早两年SVN比较火,不过被大神linus喷了几次后,就日落西山了,...

2023-10-07 12:11 guanshanw

git相关命令-上
git相关命令-上

这些命令都是看了文档后,个人觉得比较有用的一些,展示给大家。回到远程仓库的状态抛弃本地所有的修改,回到远程仓库的状态。gitfetch--all&...

2023-10-07 12:10 guanshanw

Git命令行接口:掌握Git的必备技能
Git命令行接口:掌握Git的必备技能

Git是一款强大的分布式版本控制工具,它支持命令行界面操作。熟练掌握Git命令行接口,是开发者使用Git的必备技能之一。在这篇文章中,我们将介绍Git命令行接口...

2023-10-07 12:10 guanshanw

Git命令详解
Git命令详解

相信各位小伙伴们应该都对git有一些了解,毕竟作为代码管理的神器,就算不是IT行业的小伙伴肯定也或多或少的听说过一些。今天就来和小伙伴们分享一下自己总结的常用命...

2023-10-07 12:10 guanshanw

工作7年收集到的git命令
工作7年收集到的git命令

概念git中的术语解释:仓库也叫版本库(repository)stage:暂存区,add后会存到暂存区,commit后提交到版本库git安装linux...

2023-10-07 12:10 guanshanw

取消回复欢迎 发表评论: