Maven依赖解析

小说:重觅旧恋--寻找早已消逝的情人作者:邓开更新时间:2019-03-24字数:94758

水无月白很喜欢和刘皓等人在一起的生活,她绝对不允许有人破坏她这种生活,因此水无月白如同雪一般毫无杂质的目光此时也出现了大自然冰天雪地对生命的无情寒冷,放佛水无月白化作了冰雪要将两个胆敢踏入冰雪世界的飞段和角都给冻结冰封似的。

讨论:奸淫幼女算不算强奸?

剑尖越来越近,出手之人面露笑意,一瞬间,眼前为之一空,林风根本没有时间去看,那一瞬间完全凭借直觉,整个身子瞬间弹出。
一个金仙中期的存在能轻而易举的十个金仙初期的存在,这里的差距可想而知了,而中期和后期之间的差距比起初期和中期之间的差距更大,之后就更是如此。

“居然敢无视老子。”战桃丸一手推出去,武装色霸气推动之下产生惊人的力量,这一下子被打中的话,布玛也不好受。

 本文将记录Maven工程中依赖解析机制,内容包括:

  1. Maven依赖基本结构
  2. 从仓库解析依赖的机制
  3. 依赖传递性解析实例

1. Maven依赖基本结构

上篇文章记录了Maven依赖的聚合与继承,POM中依赖的声明通过dependency进行定义,并且通过groupId、artifactId及version三项定位Maven库中的唯一依赖。除了这三项外,还有其他属性进行限制,如下:

 1 <dependencies>
 2    <dependency>
 3      <groupId>...</groupId>
 4      <artifactId>...</artifactId>
 5      <version>...</version>
 6      <type>...</type>
 7      <scope>...</scope>
 8      <optional>...</optional>
 9      <exclusions>
10         <exclusion>
11             <groupId>...</groupId>
12             <artifactId>...</artifactId>
13         </exclusion>
14      </exclusions>
15    </dependency>
16 </dependencies>
  • groupId、artifactIdversion三项不再叙说;
  • type:依赖类型,对应于项目坐标定义的packaging,默认为jar;
  • scope:依赖范围,包括compile、test、runtime、import、provided、system;
  • optional:标记依赖为可选,即依赖没有传递性;
  • exclusions:排除传递性依赖

1.1 依赖范围

  我们知道,Maven工程约定具有固定的目录结构,以便于Maven各插件对工程处理,如编译(compile)插件,会将src/main/java中的类编译到target/classes目录下,则编译对应的classpath即为target/classes。依赖范围就是控制依赖于编译classpath(target/classes)、测试classpath(target/test-classes)和运行classpath(以Web工程为例,WEB-INF/classes)的关系。具体依赖范围的讲述可参考官网文档,在此仅进行稍微总结:

  • compile:编译依赖范围,对编译、测试、运行classpath都有效,为默认范围;
  • test:测试依赖范围,仅对测试classpath有效;
  • runtime:运行时依赖范围,对测试和运行classpath有效,对编译无效,如JDBC的依赖引入,因为JDK中值声明了JDBC接口,具体实现由各厂家决定;
  • import:导入依赖范围,对三种classpath不产生实际影响,一般是导入pom类型的依赖,聚合情况下需要声明打包类型为pom,其中可包含dependencyManagement(如上一篇文章),此时对引入该依赖的工程不产生影响;
  • provided:已提供依赖范围,对测试和编译classpath有效,对运行时无效,如servlet-api在测试或编译的时候需要,在运行的时候由容器提供,故不需要重复引入;
  • system:系统依赖范围,与provided范围一致,需要明确指定该jar包,其不在Maven仓库中,感觉不太常用。

1.2 依赖传递性

依赖传递性,举例说明,比如A引用B,B引用C,正常情况下,A也会引用C依赖,即A经过传递间接引用了C(依赖为可选时,需另行处理)。具体不同范围的依赖经过传递后,其依赖范围的变化如下边(从官网扣下来的)

依赖传递的准则

  • 路径最近这优先,即在引用传递链上,获取出离本POM最近的传递性依赖;
  • 如果路径距离相同,则以取POM中的声明顺序靠前的。

1.3 可选依赖

   可选依赖不被传递。假设项目A依赖于B,B依赖于X和Y,并且X和Y声明为可选,则X和Y对A就不具有传递性了。如果A需要依赖于X或Y,则需要直接引用。

1.4 依赖排除

   假设项目A依赖于B,B依赖于C(版本为1.0),此时A会传递性依赖于C(1.0)。如果A需要引用C(2.0版本),存在两种情况:

  (1)A直接引用C(2.0),则可以不对B依赖添加exclusions元素;

  (2)A在引用B的同时,还引用D(D引用C(2.0)),则可以在引用B的时候使用exclusions元素将C(1.0)排除,也可以将D依赖声明在B之前。

2. 从仓库解析依赖的机制

   依赖解析的基本过程:当本地仓库中没有依赖构件,则Maven从远程仓库中下载;当依赖版本为快照版本时,Maven会自动计算最新的快照,并引用。

  背后的依赖解析机制概括如下:

  (1)当依赖的范围为system,则从本机文件系统中解析构件;

  (2)根据依赖坐标计算定位依赖位置后,尝试从本地仓库寻找依赖,若找到,则解析成功;

  (3)若本地仓库没有对应构件,则遍历所有远程仓库,发现后解析下载;

  (4)如果依赖的版本为RELEASE或LATEST,则读取所有远程仓库的元数据groupId/artifactId/version/maven-metadata.xml,与本地元数据合并后,计算出RELEASE或LATEST的真实值,然后基于真实值检查本地仓库和远程仓库,如步骤(2)(3);

  (5)如果依赖的版本为SNAPSHOT,类似的,读取远程仓库的元数据,并与本地元数据合并,计算出最新版本的快照,再从本地仓库和远程仓库检索。

 下边为一个快照版本依赖的元数据maven-metadata-local.xml,包括最近更新时间戳,以及存在的不同版本:

<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <groupId>com.test</groupId>
  <artifactId>C</artifactId>
  <versioning>
    <versions>
      <version>1.0-SNAPSHOT</version>
      <version>2.0-SNAPSHOT</version>
    </versions>
    <lastUpdated>20171113125841</lastUpdated>
  </versioning>
</metadata>

 对应文件目录结构如下:

其中每个版本中,包含对自身描述的元数据。以2.0-SNAPSHOT为例,其目录结构如下,主要包含jar和pom两部分,maven-metadata-local.xml为依赖元数据:

具体元数据内容如下,记录了该版本依赖最近一次的更新时间。在本地库中没有该构件的时候,会检索所有远程仓库,结合元数据文件,计算最新的版本;或者在进行强制更新的时候,也会计算出最新版本

<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
  <groupId>com.test</groupId>
  <artifactId>C</artifactId>
  <version>2.0-SNAPSHOT</version>
  <versioning>
    <snapshot>
      <localCopy>true</localCopy>
    </snapshot>
    <lastUpdated>20171117132322</lastUpdated>
    <snapshotVersions>
      <snapshotVersion>
        <extension>jar</extension>
        <value>2.0-SNAPSHOT</value>
        <updated>20171117132322</updated>
      </snapshotVersion>
      <snapshotVersion>
        <extension>pom</extension>
        <value>2.0-SNAPSHOT</value>
        <updated>20171117132322</updated>
      </snapshotVersion>
    </snapshotVersions>
  </versioning>
</metadata>

3. 依赖传递性解析实例

   创建3个Maven工程A、B、C(命令mvn archetype:generate)。

  (1)编辑各自的POM文件,使其依赖关系如下图所示

                    

其中B为A的直接依赖,C具有传递性,为A的传递性依赖,分析其依赖树可以直观的看出依赖关系(mvn dependency:tree),如下:

  • B依赖于C(1.0)

  •  A依赖于B(1.0),间接依赖C(1.0)

(2)将B对的C的依赖改为optional,即可选的,此时A的依赖树如下,不包括C:

(3)修改POM文件,使其依赖关系如下:

          

 看A的依赖树,如下:

 综上,正常情况下依赖是具有传递性,除非声明为optional。

总结:

  • 声明依赖时,除了常用的三项位置元素,还具有包括范围、类型、可选和排除等;
  • 依赖具有传递性,具有路径优先的约定;
  • 当引用多个工程时,会潜在的引用其他依赖,需要注意是否会引错包,或者冲突;
  • Maven依赖解析,对于本地库中没有的构件,Maven会综合远程仓库与本地仓库的元数据,计算最新版本后,再引用。

参考:

  • Introduction to the Dependency Mechanism

  • 《Maven实践》

编辑:秉安

发布:2019-03-24 03:21:57

当前文章:http://leetaemin.cn/array/dtg5l9emzj.html

文化优化 茶叶的基本分类,品质的概念。 你真的适合创业吗?答案是“未必”! 这年头,和尚泡妞都这么骚气 欧美同学会是干什么的? 突破“离婚”或“凑合过”的婚姻困惑 【双章书法】系列:张肇达书法 - 黄胤然诗联 老子之励志

74939 14732 19369 66576 96920 69160 46571 36263 69927 25965 57852 50923 68122 55645 38603 64467 78974 15287 45772 58910

我要说两句: (0人参与)

发布