前面我们讲了maven项目中的最重要的文件:pom.xml 配置文件相关内容。介绍了pom 是如何定义项目,如何添加依赖的jar 包的等。

我们知道,在Maven的生命周期中,存在编译、测试、运行等过程,那么有些依赖只用于测试,比如junit;有些依赖编译用不到,只有运行的时候才能用到,比如mysql的驱动包在编译期就用不到(编译期用的是JDBC接口),而是在运行时用到的;还有些依赖,编译期要用到,而运行期不需要提供,因为有些容器已经提供了,比如servlet-api在tomcat中已经提供了,我们只需要的是编译期提供而已。

那么Maven是如何管理各个jar包的依赖关系,jar包之间的依赖传递和依赖冲突呢?所以接下来就讲一讲maven的依赖管理。

一、声明依赖

Maven 项目使用pom.xml 文件,可以方便的管理项目中所有依赖的jar包,之前也介绍过pom.xml 文件是如何定义依赖的。下面就以一段 junit依赖声明,演示pom.xml 是如何定义相关依赖的:

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<type>jar</type>
<scope>test</scope>
<optional>false</optional>
<exclusions>
<exclusion></exclusion>
</exclusions>
</dependency>
</dependencies>

上面的示例我们定义了junit的依赖,而且junit只在测试阶段生效。具体配置参数如下:

  • type:依赖类型,对应构件中定义的 packaging,可不声明,默认为 jar;
  • scope:依赖范围,大致有compile、provided、runtime、test、system等几个;
  • optional:依赖是否可选;
  • exclusions:排除传递依赖。

总结说来,在pom.xml 配置文件中,配置节点引入了节点,它主要管理依赖的范围。大致有compile、provided、runtime、test、system等几个。引入 节点排除某些依赖。解决了控制各个jar包的依赖范围,jar包之间的依赖传递和依赖冲突的问题。

二、依赖范围

Maven在执行不同的命令时(mvn package,mvn test,mvn install ……),会使用不同的 classpath,Maven 对应的有三套 classpath,即:编译classpath、测试classpath,运行classpath。我们可在dependency中的scope元素中进行配置。从而决定了该依赖构件会被引入到哪一个 classpath 中。默认为:compile。Maven提供的依赖范围如下:

  • compile:编译依赖范围,默认值。此选项对编译、测试、运行三种 classpath 都有效,如 hibernate-core-3.6.5.Final.jar,表明在编译、测试、运行的时候都需要该依赖;
  • test:测试依赖范围。只对测试有效,表明只在测试的时候需要,在编译和运行时将无法使用该类依赖,如 junit;
  • provided:已提供依赖范围。编译和测试有效,运行无效。如 servlet-api ,在项目运行时,tomcat 等容器已经提供,无需 Maven 重复引入;
  • runtime:运行时依赖范围。测试和运行有效,编译无效。如 jdbc 驱动实现,编译时只需接口,测试或运行时才需要具体的 jdbc 驱动实现;
  • system:系统依赖范围。和 provided 依赖范围一致,也是编译和测试有效,需要通过  显示指定,且可以引用环境变量;
  • import:导入依赖范围。使用该选项,通常需要 pom,将目标 pom 的 dependencyManagement 配置导入合并到当前 pom 的 dependencyManagement 元素。

需要注意的是,在打包阶段,使用的是运行classpath。即引入到运行classpath中的Maven依赖会被一起打包。

三、依赖传递

所谓依赖传递,就是A依赖B,B依赖C,A就间接依赖C,那么A与C直接的依赖关系就叫传递性依赖。

直接依赖又叫第一直接依赖,传递性依赖又叫第二直接依赖,其中第一直接依赖和第二直接依赖的依赖范围,决定了传递性依赖的依赖范围。

下面使用hibernate-core的依赖关系详细介绍所谓的依赖传递:

如上图所示,hibernate-core 依赖 hibernate-commons-annotations ,而 hibernate-commons-annotations 又依赖 slf4j-api ,hibernate-core 对 slf4j-api 的依赖就是传递依赖。pom.xml 文件中我们只需要引入 hibernate-core 构件的依赖,Maven 会自动为我们引入依赖jar包及传递依赖的jar包,无需再手动引一遍相关依赖。所以不用担心依赖冲突的问题。

那么如何判定一个间接依赖是否有必要被引入呢?间接依赖被引入后其依赖范围又是什么呢?

其实很简单,就是通过第一直接依赖的依赖范围和第二直接依赖的依赖范围之间的关系,来判定是否有必要引入间接依赖以及确定引入间接依赖后其依赖范围,如下表所示:

所以,通过上表我们可以发现:

1)第二直接依赖的依赖范围为compile : 传递依赖的依赖范围同第一直接依赖的依赖范围一样。

2)第二直接依赖的依赖范围为test : 传递依赖不会被引入。

3)第二直接依赖的依赖范围为provided : 只有当第一直接依赖的依赖范围亦为provided时,传递依赖才会被引入,且依赖范围依然是provided。

4)第二直接依赖的依赖范围为runtime : 除了第一直接依赖的依赖范围为compile时传递依赖的依赖范围为runtime外,其余情况下,传递依赖的依赖范围同第一直接依赖的依赖范围一样。

四、依赖冲突

通常我们不需要关心传递性依赖,但是当多个传递性依赖中有对同一构件不同版本的依赖时,如何解决呢?通常我们有一下两个原则:

  • 短路径优先:假如有以下依赖:A -> B -> C ->X(版本 1.0) 和 A -> D -> X(版本 2.0),则优先解析较短路径的 X(版本 2.0);
  • 先声明优先:即谁先声明,谁被解析。

针对依赖冲突中的“短路径优先”,那如果我们就想使用长路径的依赖怎么办呢?这时可以使用依赖排除元素,显示排除短路径依赖。在非冲突的情况下,这种方法同样有效。

五、解决依赖冲突

一般情况下我们不需要关心依赖的问题。而当依赖出问题时,我们需要知道该如何解决依赖冲突。解决依赖冲突的方式如下:

(1)首先,使用:mvn dependency:tree 命令查看项目的依赖列表,

(2)然后,通过依赖列表,找出冲突的jar包。

(3)最后,可选依赖 option或是排除依赖 exclusions 处理相关冲突。

1.可选依赖 option

通过项目中的pom.xml中的dependency下的option元素中进行配置,只有显式地配置项目中某依赖的option元素为true时,该依赖才是可选依赖;不设置该元素或值为false时,作用是:当某个间接依赖是可选依赖时,无论依赖范围是什么,其都不会因为传递性依赖机制而被引入。

        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!-- optional=true,依赖不会传递,该项目依赖devtools;之后依赖boot项目的项目如果想要使用devtools,需要重新引入 -->
<optional>true</optional>
</dependency>

上面的示例,当optional=true,devtools的依赖不会传递,该项目依赖devtools;之后依赖该项目的项目则不会依赖devtools组件,如果想要使用devtools,需要重新引入。

2.排除依赖 exclusions

我们知道,由于Maven的的传递性依赖机,有时候第三方组件B的C依赖由于版本(1.0)过低时。我们期望能够将该间接依赖直接剔除出去,这样不会影响到项目中其他依赖组件。这时可以通过exclusions元素实现。

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>

上面,我们排除了spring-core组件忠的commons-logging。

最后

以上,我们就把Maven的依赖关系,Jar包之间的依赖传递和依赖冲突介绍完了。

Maven快速入门(五)Maven的依赖管理的更多相关文章

  1. (4)Maven快速入门_4在Spring+SpringMVC+MyBatis+Oracle+Maven框架整合运行在Tomcat8中

    利用Maven 创建Spring+SpringMVC+MyBatis+Oracle 项目 分了三个项目  Dao   (jar)   Service (jar)   Controller (web) ...

  2. Maven快速入门(一)Maven介绍及环境搭建

    做开发的程序员都知道,在系统开发需要各自各样的框架.工具.其中有一种工具不管你是初级程序员还是高级程序员都必须熟练掌握的,那就是项目管理工具(maven.ant.gradle).接下来就总结Maven ...

  3. Maven快速入门(二)手动创建maven项目hellomaven

    之前讲过Maven介绍及环境搭建,介绍了maven的作用和如何搭建maven环境.接下来就以一个helloworld的例子来说一说如何创建maven项目以及maven项目的项目结构,最后讲maven如 ...

  4. Maven快速入门(三)Maven的坐标和仓库

    之前通过一个helloworld的例子来说一说如何创建maven项目以及maven项目的项目结构,然后讲maven如何编译运行项目.接下来介绍maven中几个比较重要的概念:坐标和仓库.Maven快速 ...

  5. Java实战及解析 — Maven快速入门

    五分钟快速入门 mvn --version mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -Darche ...

  6. (1)Maven快速入门_1maven安装

    Maven 快速入门 1.1 Maven官网下载     windows 系统 下载 下图红色框选处. 下载到本地解压, 创建一个本地maven仓库的目录 maven_lib 配置Maven的环境变量 ...

  7. (5)Maven快速入门_5maven聚合与继承_scope依赖范围

    多个maven项目实现统一管理, maven 插件jar继承自父的maven项目.对maven中jar的版本进行管理. 1.创建一个项目来管理多个maven项目 new ----maven Proje ...

  8. Maven——快速入门手册(学习记录)

    前言: 前段时间进行了一点maven的入门学习,在这里做个记录,希望能帮到一些正在学习的朋友们.maven版本为3.3.9.希望大家觉得好的点个赞,觉得不好的多提提意见和建议做个交流.这里也贴出我学习 ...

  9. Maven快速入门使用

    1. Maven 介绍 1.1 为什么使用 Maven 由于 Java 的生态非常丰富,无论你想实现什么功能,都能找到对应的工具类,这些工具类都是以 jar 包的形式出现的,例如 Spring,Spr ...

随机推荐

  1. 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程 | 百篇博客分析OpenHarmony源码 | v59.01

    百篇博客系列篇.本篇为: v59.xx 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿 ...

  2. SQL Server附加数据库错误5120处理方法

    SQL Server附加数据库5120错误 当我们从另外一台服务器复制过来的数据库,可能会有如下错误: 解决方法 1.给数据库所在文件夹增加用户Everyone并赋予完全控制权限 2.以管理员身份运行 ...

  3. 通用JS七

    instanceof 在原型链上寻找这个属性的定义 match 正则匹配字符串 Symbol() Symbol()函数不能用作构造函数,与new关键字一起使用.这样做是为了避免创建符号包装对象,像使用 ...

  4. 实验2:Open vSwitch虚拟交换机实践

    作业链接:实验2:Open vSwitch虚拟交换机实践 一.实验目的 能够对Open vSwitch进行基本操作: 能够通过命令行终端使用OVS命令操作Open vSwitch交换机,管理流表: 能 ...

  5. 小白自制Linux开发板 番外篇 一 modprobe加载驱动问题(转载整理)

    使用modprobe加载驱动 转载地址:https://blog.csdn.net/qq_39101111/article/details/78773362 前面我们提到,modprobe并不需要指定 ...

  6. 重庆邮电大学第十一届ACM程序设计竞赛-网络选拔赛 C题

    1008: 偷袭 时间限制: 1.000 sec 内存限制: 128 MB 武林要以和为贵,张麻子不讲武德来偷袭马老师的亲传弟子. 马老师有n个亲传弟子,每个弟子有一个武力值a[i]. n个弟子中只有 ...

  7. 第十一章 Dockerfile安装Jenkins-2.249.3-1.1

    一.安装Docker Docker部署Jenkins前提已经安装Docker,这边脚本安装Docker. #1.编写Docker安装脚本 [root@ip-10-0-12-212 ~]# vim In ...

  8. print spooler LPF 打印机漏洞

    打印机漏洞 该漏洞可以通过创建打印机驱动和端口,实现任意文件写入,用于提权或者写入后门. 打印机调用流程:client通过RPC调用server的spoolsv.exe,spoolsv.exe是sys ...

  9. 如何查找一个目录中所有c文件的总行数

    如何查找一个目录中所有c文件的行数 面试题问到了一题,如何统计wc文件夹下所有文件的行数,包括了子目录. 最后在 https://blog.csdn.net/a_ran/article/details ...

  10. 【转载】[经验] 嵌入式stm32实用的排序算法 - 交换排序

    Ⅰ.写在前面 前面写了关于ADC采集电压的文章,大家除了求平均的方式来处理采样值,还有没有使用到其他的方式来处理采集值呢? 在某些情况下就需要对一组数据进行排序,并提取头特定的数据出来使用. 排序的应 ...