阅读 96

Maven依赖那些事儿

依赖的配置

一个依赖声明可以包含如下元素

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

根元素的project下的dependencies可以包含一个或者多个dependency元素,以声明一个或者多个项目依赖。每个项目可以包含的元素有:

  • groupIdartifactIdversion
    依赖的基本坐标,对于任何一个依赖来说,基本坐标是最重要的、Maven根据坐标才能找到所需要的依赖
  • type
    依赖的类型,大部分情况下不必设置,默认值为jar
  • scope
    依赖的范围
  • optional
    标记依赖是否可选
  • exclusions
    用来排除传递性依赖

依赖范围

首先需要知道Maven对于编译、测试、运行使用三套不同的classpath,Maven依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系

  • compile
    编译依赖范围。默认依赖范围。对于编译、测试、运行三种classpath都有效
  • test
    测试依赖范围。只对测试classpath有效,典型的例子是JUnit,它只有在编译测试代码及运行测试的时候才需要
  • provided
    已提供依赖范围。对于编译和测试classpath都有效,典型的就是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要maven重复地引用一遍
  • runtime
    运行时依赖范围。对于测试和运行classpath都有效,典型例子就是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动
  • system
    系统依赖范围。对于编译和测试classpath都有效,需要与systemPath配合使用指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此谨慎使用
  • import(Maven 2.0.9及以上)
    导入依赖范围
依赖范围scope 对于编译classpath有效 对于测试classpath有效 对于运行classpath有效 例子
compile Y Y Y spring-core
test - Y - Junit
provided Y Y - servlet-api
runtime - Y Y JDBC驱动实现
system Y Y - 本地的,Maven仓库之外的类库文件

传递性依赖

何为传递性依赖

如下图,假设A模块与B模块的依赖范围都为默认compile,那么C模块就会成为A模块的compile范围依赖,C模块是A模块的一个传递性依赖


有了传递性依赖机制,就不需要考虑一个模块所依赖了什么,也不用担心引用多余的依赖。Maven会解析各个直接依赖的POM,将那些必要的间接依赖以传递性依赖的形式引入到当前的项目中

传递性依赖和依赖范围

依赖范围不仅可以控制依赖与三种classpath的关系,还对传递性依赖产生影响
如下图,A依赖于B并且称为第一依赖,B依赖于C并且称为第二依赖,A对于C是传递性依赖由第一依赖第二依赖的依赖范围决定


如下表所示,左边一列为第一依赖,最上面一行为第二依赖,中间的交叉单元格则表示传递性依赖

第一依赖\第二依赖 compile test provided runtime
compile compile - - runtime
test test - - test
provided provided - provided provided
runtime runtime - - runtime

依赖调解

当传递性依赖造成问题的时候,我们需要清楚地知道该传递性依赖是从那条依赖路径引入的

Maven依赖调解(Dependency Mediation)共有两条原则

  • 路径最近者优先
    如,A项目存在如下依赖:
    A -> B -> C -> X(1.0)A -> D -> X(2.0)
    X(1.0)的路径为3,而X(2.0)的路径为2,因此X(2.0)会被解析使用
  • 第一声明者优先
    如,A项目存在如下依赖:
    A -> B -> Y(1.0)A -> C -> Y(2.0)
    依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用,如B的依赖声明在C之前,那么Y(1.0)就会被解析使用

可选依赖-optional

  • 为什么?
    比如项目B实现了两个特性,其中的特性一依赖于X,特性二依赖于Y,而且这两个项目是互斥的,用户不可能同时拥有两个特性,比如B是持久化层隔离工具包,在构建时需要两种数据库的驱动程序,但在使用这个工具包的时候,只会依赖一种数据库
  • 依赖关系
    如图,如果这三个依赖的范围都是compile,那么X、Y就是A的compile范围传递性依赖。然而由于X、Y为可选依赖,依赖并不会得到传递


:在理想情况下,是不应该使用可选依赖的。使用可选依赖的原因是某个项目实现了多个特性,在面向对象程序设计中,有个单一职责性原则,意指一个类应该只有一项职责,而不是揉合太多的功能

作者:quanCN

原文链接:https://www.jianshu.com/p/eafd786b012a

文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐