引言

在Maven 中,依赖有一些特性必须我们掌握,如依赖的传递性。

一、依赖的传递性

其实依赖的传递性非常好理解。

上图,如果 Maven 项目 B 已经依赖了 C ,A 又依赖了 B,那么 A 不需要再在自己的pom 中重复引入 C 的依赖声明,就可以直接使用 C 中的代码了。

显而易见,依赖能够传递的好处就是,不必反复声明相同的依赖,在“最下面” 的工程中依赖一次就可以。在实际开发中,往往会有一个专门管理依赖的模块项目。

不过这种情况不是绝对的,这里有一个非常关键的限制,即依赖的 Scope

Scope 指的是“作用域”,对于依赖来说,就指的是某个依赖是否参与 compile 、test、打包等几个重要的事件。

我们在pom 中声明 <dependency> 的时候,可以顺便声明<scope>,默认情况下是就是 compile 。对于 scope 是 compile 的依赖,上面的依赖传递关系是成立的,即 A 可以不必明确声明依赖 C 就能使用C 中的代码。

另外,虽然依赖的传递性非常方便,但并不适合所有场景,有些情况下,是需要进行直接依赖的,比如,当模块项目进行拆分重组,那么有些间接依赖可能就会被切断传递的链路,这种情况,就需要在搭建项目之初考虑到这个问题。

二、依赖的作用域

我在网上看到一些对maven 依赖的 scope 属性的讲解,貌似都不太敢于称其为“作用域”,不过我觉得“作用域”这个翻译应该是比较合适的。

引述一下官网的描述:

Dependency scope is used to limit the transitivity of a dependency, and also to affect the classpath used for various build tasks.

依赖作用域用来限制一个依赖的传递性,同时也可以影响类路径下多种构建任务

2.1 compile

默认值, scope 声明为 compile 的依赖对项目所有类路径都可用,即对于编译、测试、运行三个状态都有效。此外,这样的依赖还可以在依赖它的项目中进行传递。

2.2 test

也是一个比较常用的取值,需要显式声明。最常见的使用 test 作为作用域的依赖就是 JUnit,它代表此依赖在正常使用时是不要求的(is not required for normal use of the application),例如:

<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>

被声明为 test 作用域的依赖,值针对test 代码,且无法进行依赖传递

2.3 provided

这个类型的 scope 和 compile 比较像。对于编译和测试有效,但运行时无效,典型的如servlet-api,运行时这个由容器来提供。简单的说,就是作用域为 provided 的依赖,可以参与 编译、测试等工作,相当于 compile 作用域,但是在打包的时候不需要打入包中,即在打包阶段做了 exclude 操作。此类型的依赖也是不能传递的

2.4 runtime

不太常用,对测试和运行有效,但编译无效。可以简单理解为对 provided 的一种互补。

2.5 system

与provided的范围一样,但system必须显示的指定依赖文件,通过<systemPath>来进行指定,是与本机绑定的,所以基本很少用到。

2.6 import

这是唯一一个只能在 <dependencyManagement> 中使用的scope 类型。最常见的用法是引入 scope = import 的spring-boot-dependencies,这个依赖是连spring-boot-starter-parent都需要继承的父工程,用于进行诸多依赖版本的管理,使用方式是:

<dependencyManagement><dependencies><dependency><!-- Import dependency management from Spring Boot --><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>1.5.2.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>

这些 scope 对编译、测试、运行可用的一览表:

scope 编译 测试 运行
compile Y Y Y
test   Y  
provided Y Y  
runtime   Y Y
system Y Y  

三、作用域的传递性问题

scope 除了限制了依赖能够参与编译、测试、打包(运行)等工作外,还会对依赖的传递性有所影响,注意区分这两个知识点。

前面也已经提到,如果是默认的 compile 作用域,那么依赖会一直传递下去,不受任何影响,而 test 作用域的依赖,就无法进行依赖传递。

四、依赖的原则

在项目中,依赖往往遵循两个原则:

4.1 路径最短优先原则

当有同种依赖不同版本的时候,依照“路径最短者优先原则”。即默认使用层级关系最近的传递依赖。

4.2 先声明者优先原则

当路径距离相同时,根据“先声明者优先原则”来取舍。即dependency标签在上面的优先使用传递依赖。

如上图中 ,在 A 的pom 中如果 先声明了 C ,那么,将会优先使用 log4j.1.2.17版本。

五、依赖的排除

当我们不希望使用某些传递过来的依赖时可以使用这种方式,可能由于自动传递过来的此依赖版本不稳定,想替换成其他的依赖等等。

设置方式是在希望排除某个依赖的工程中配置<exclusions>标签即可。需要填写groupId和artifactId两项,那么不管什么版本的依赖都会被直接排除掉。另外,可以在层级视图中打开pom:

六、统一管理依赖版本

前面的文章中,介绍了通过父工程来管理子工程共同的一些依赖的版本号,然后在子工程中就不需要重复进行版本号的声明。

另外在一些只作用于当前pom 的版本号控制可以使用 <properties> 标签来声明,不仅仅是统一的版本号,项目编译、打包时的编码也可以进行指定。

 <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>

Maven学习(五)————依赖的特性辨析相关推荐

  1. Maven学习:依赖管理

    依赖是什么? "依赖是maven项目引用的资源jar包,依赖范围就是这些资源架包在maven项目中的作用范围,反过来说,maven项目通过依赖范围来控制何时引用资源jar包." 关 ...

  2. Maven学习总结(五)——聚合与继承

    2019独角兽企业重金招聘Python工程师标准>>> Maven学习总结(五)--聚合与继承 一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1. ...

  3. Maven学习(二) -- 坐标和依赖

    标签(空格分隔): 学习笔记 坐标 实际就像在几何中,我们用一对坐标(x, y)来表示坐标系中唯一的点:或者我们可以用(经度,纬度)来表示地球上的某一个位置,在Maven的世界中,有坐标来唯一的表示项 ...

  4. Maven学习(二) -- 坐标和依赖(转自--江湖小妞)

    坐标 实际就像在几何中,我们用一对坐标(x, y)来表示坐标系中唯一的点:或者我们可以用(经度,纬度)来表示地球上的某一个位置,在Maven的世界中,有坐标来唯一的表示项目. 他们由groupId,  ...

  5. 【记录ROS学习(五)2022/08/27】Win版ROS/Noetic 如何添加必要的依赖(rosdep)

    [记录ROS学习(五)2022/08/27]Win版ROS/Noetic 如何添加必要的依赖(rosdep) 近期为了使得更多的设备可以连入ROS,开始转向Windows平台的ROS,遇到一些问题 无 ...

  6. Maven学习总结(八)——使用Maven构建多模块项目

    2019独角兽企业重金招聘Python工程师标准>>> Maven学习总结(八)--使用Maven构建多模块项目 在平时的Javaweb项目开发中为了便于后期的维护,我们一般会进行分 ...

  7. Maven学习总结(四)——Maven核心概念

    2019独角兽企业重金招聘Python工程师标准>>> Maven学习总结(四)--Maven核心概念 一.Maven坐标 1.1.什么是坐标? 在平面几何中坐标(x,y)可以标识平 ...

  8. Maven学习总结(一)——Maven入门

    2019独角兽企业重金招聘Python工程师标准>>> Maven学习总结(一)--Maven入门 一.Maven的基本概念 Maven(翻译为"专家",&quo ...

  9. Maven学习(一)——Maven入门

    为什么80%的码农都做不了架构师?>>>    一.Maven的基本概念 Maven(翻译为"专家","内行")是跨平台的项目管理工具.主要服 ...

最新文章

  1. Visual Studio环境变量使用实例:使用环境变量来组织project
  2. 12月国内网站流量统计5强:360安全中心后来居上
  3. 计算机组成原理——总线结构
  4. python类的实例方法必须创建对象前还是后可以调用_classmethod可以来调用类的属性,类的方法,实例化对象...
  5. SpringBoot中定义全局异常处理器
  6. 【转】sql表及字段命名规范
  7. 44个Java代码性能优化总结
  8. php异步发送邮件,php通过fsockopen异步发送邮件
  9. 能够帮助确诊乳腺癌的AI系统诞生,堪称“女性之友”
  10. android音乐播放器flac,五款Android手机FLAC,APE无损音乐播放器
  11. win10计算机文件坏了,win10电脑电脑注册表文件丢失或损坏0xc0000e9怎么办
  12. 从有赞UI组件库看CSS BEM命名规范的好处
  13. vulhub-activemq-cve-2015-5254
  14. 电压模块THM30-2421WI
  15. 独立IP、特产浏览量(PV)、访问次数(VV)、独立访客(UV)
  16. python中库是什么意思,python中的库、包、模块和脚本是什么意思
  17. 51单片机(二十七)—— 蜂鸣器播放音乐
  18. Uncaughr SyntaxError:Ivalid or unexpected toke(JS)
  19. 2020数据架构师面试题库
  20. 通达OA前台任意用户登录漏洞+RCE漏洞复现

热门文章

  1. java 生产者消费者代码_Java生产者和消费者代码
  2. 报告老板:这次的缓存事故是这样的...
  3. Redis笔记之基本数据结构 动态字符串SDS
  4. Tensorflow中查看gpu是否可用
  5. Git报错: OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443
  6. std::dynamic_pointer_cast细节用法
  7. ArrayList list = new ArrayList(20);中的list扩充几次
  8. websocket一直无法链接_.NET Core 实现基于Websocket的在线聊天室
  9. 应运ajax的几种语言,Ajax指的是什么
  10. mysql设置输出格式_rsyslog 配置mysql输出格式