专栏首页维C果糖详述 Maven 依赖范围及依赖调节原则

详述 Maven 依赖范围及依赖调节原则

当在我们 POM 文件中配置 Maven 依赖的时候,常见的格式如下:

<project>
    ...
    <dependencies>
        <dependency>
            <groupId>...</groupId>
            <artifactId>...</artifactId>
            <version>...</version>
            <type>...</type>
            <scope>...</scope>
            <optional>...</optional>
            <exclusions>
                <exclusion>
                    ...
                </exclusion>
                ...
            </exclusions>
        </dependency>
        ...
    </dependencies>
    ...
</project>

其中,groupId、artifactId 和 version 是 Maven 依赖的基本坐标,也是最重要的。其他的元素如 type 表示依赖的类型,默认为jar;scope 为依赖的范围,默认为compile;optional 用来标记依赖是否可选;exclusions 用来排除传递性依赖。

现在我们所要讲的依赖范围,正是其中 scope 元素所能选择的内容。在正式介绍依赖范围之前,我们需要知道一件事,那就是:Maven 项目的环境变量(classpath)有三种,分别为编译时用的环境变量、测试时用的环境变量和运行时用的环境变量。而依赖范围就是用来控制依赖与这三种环境的关系的:

  • compile:编译依赖范围,此为默认值,对编译、测试和运行三种环境变量都有效。
  • test:测试依赖范围,仅对测试环境变量有效。
  • provided:已提供的依赖范围,对编译和测试环境变量都有效。
  • runtime:运行依赖范围,对测试和运行环境变量都有效。
  • system:系统依赖范围,对编译和测试环境变量都有效,但由于此依赖不是通过 Maven 仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。
  • import:导入依赖范围,并不会对上面的三种环境变量产生实际的影响。

依赖范围(scope)

编译环境变量有效

测试环境变量有效

运行环境变量有效

compile

Y

Y

Y

test

N

Y

N

provided

Y

Y

N

runtime

N

Y

Y

system

Y

Y

N

如上图所示,此为 Maven 的直接依赖范围。除此之外,还有传递性依赖,那么何为传递性依赖呢?

举一个简单的例子,在默认依赖范围的情况下,如果项目 A 依赖 B,B 依赖 C,那么 A 就依赖 C,这时 A 与 C 就是传递性依赖的关系。而且我们称 A 对 B 的依赖为第一直接依赖,B 对 C 的依赖为第二直接依赖,以此类推。

至于为什么要强调在默认依赖范围的情况下,则是传递性依赖也是有条件的,具体如下图所示:

第一直接依赖 \ 第二直接依赖

compile

test

provided

runtime

compile

compile

——

——

runtime

test

test

——

——

test

provided

provided

——

provided

provided

runtime

runtime

——

——

runtime

观察上表,我们会发现:当第二直接依赖为compile时,则依赖关系以第一直接依赖为准;当第二直接依赖为test时,则没有依赖关系;当第二直接依赖为provided时,只有第一直接依赖也为provided时才有provided范围的依赖关系;当第二直接依赖为runtime时,除了第一直接依赖关系为compile时依赖范围为runtime,其他三种皆与第一直接依赖范围相同。

此外,有一些特殊的依赖情况,可能会造成一些困扰和问题,例如:

  • 第一种依赖路径:A -> B -> C -> D(1.0)
  • 第二种依赖路径:A -> B -> D(1.1)

其中->表示依赖。如上面所示,项目 A 通过不同的路径都依赖到了项目 D,但 D 有两个不同的版本,这时怎么办?

对于这种情况,Maven 给出了一种解决方案,即:路径最近者优先。以上面的案例为例,第一种依赖路径的距离为3,第二种依赖路径的距离为2,因此这时就以第二种依赖路径为准,即依赖D(1.1)而不是D(1.0)

不过,大家有没有想过:如果两种依赖路径的距离相同该怎么办呢?例如:

  • 第一种依赖路径:A -> B -> D(1.0)
  • 第二种依赖路径:A -> B -> D(1.1)

对于这种情况,在 Maven 2.0.9 之前是不能确定到底谁被依赖的,也就造成了依赖不确定性。但是在 Maven 2.0.9 之后,Maven 给出了解决方案,即:第一声明优先。简而言之,谁先声明就依赖谁。

最后,给出一些比较有用的 Maven 命令,通过这些 Maven 命令,我们能够快速了解 Maven 的依赖情况:

  • mvn dependency:list:查看 Maven 依赖列表,包直接依赖与传递性依赖。
  • mvn dependency:tree查看 Maven 依赖树,可以清晰的看出依赖情况。
  • mvn analyze:分析 Maven 依赖的使用情况。

对于 Maven 这个优秀的构建工具、依赖管理工具、项目管理工具,值得我们花些时间去了解和掌握它!祝好。

温馨提示:此文的构思缘起于徐晓斌所著的《Maven实战》。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 通过 Git 将代码提交到 GitHub(上)

    1 前言 在「利用 SSH 完成 Git 与 GitHub 的绑定」一文中,我们完成了本地 Git 与远程 GitHub 的绑定,这意味着我们已经可以通过 Gi...

    CG国斌
  • 并发实战 之「 线程安全性」

    在早期的计算机中不包含操作系统,它们从头到尾只能执行一个程序,并且这个程序能访问计算机中的所有资源。在这种环境中,不仅程序难以编写和运行,而且对于昂贵且稀有的计...

    CG国斌
  • 快速搭建 HDFS 系统(超详细版)

    首先,准备 5 台虚拟机,其中 1 台虚拟机作为NameNode,4 台虚拟机作为DataNode,分别为:

    CG国斌
  • 6、Java包的命名与划分

    包的命名与划分 (一)使用Java包的目的 在了解做一件事之前,需要了解做这件事的目的。而使用Java包的目的大概如下: 1    对类进行归类,便于开发查找。...

    YGingko
  • Maven学习笔记四(坐标和依赖)

    IT故事会
  • 《你必须知道的.NET》读书笔记三:体验OO之美

    此篇已收录至《你必须知道的.Net》读书笔记目录贴,点击访问该目录可以获取更多内容。

    Edison Zhou
  • 一文彻底搞清Gradle依赖

    作者:曾是放牛娃 https://www.jianshu.com/p/59fd653a54d2

    用户1269200
  • 好机会,我要帮女同事解决Maven冲突问题

    任何一个职业,女生都有绝对的优势。更别提 IT 行业了,在部门中要是有女程序猿那肯定是香饽饽,备受呵护呀。

    猿天地
  • Maven依赖和冲突

    maven的核心就是依赖管理,在模块过多,之间的依赖关系也很复杂,maven提高了一个高效的管理方法。

    OPice
  • 走进JavaWeb技术世界12:从手动编译打包到项目构建工具Maven

    本文是微信公众号【Java技术江湖】的《走进JavaWeb技术世界》其中一篇,本文部分内容来源于网络,为了把本文主题讲得清晰透彻,也整合了很多我认为不错的技术博...

    Java技术江湖

扫码关注云+社区

领取腾讯云代金券