Maven实战07_依赖

1:依赖声明

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

解释说明:

  • 根元素prject下的dependencies可以包含一个或所个dependency元素,以声明一个或多个项目依赖
  • groupId、artifactId、version:依赖的基本坐标,每一个依赖必须具备的属性,Maven只有根据这些坐标才能找到并下载依赖
  • type:依赖的类型,对应于项目坐标定义的packaging。大部分情况下,不必声明,默认为jar
  • scope:依赖的范围,见下面2:依赖范围
  • optional:标记依赖是否可选,见下面4:依赖可选
  • exclusion:用来排除传递性依赖,见下面3:传递性依赖

2:依赖范围(用于确认是否可导入依赖包)

Maven在编译项目主代码的时候需要使用一套classpath。例如,邮件模块中的javax.mai依赖会出现

Maven在编译和执行测试的时候会使用另一套classpath。例如,Juni依赖t只会出现在测试classpath下,javax.mail也会出现

Maven在运行实际项目的时候,又会使用一套classspath。例如,javax.mail需要出现,junit则不需要出现。

依赖范围就是用来控制依赖与这三种classpath的(编译classpath、测试classpath、运行classpath)的关系,Maven有以下几种依赖范围:

  • compile:编译依赖范围。如果没有指定,默认的依赖范围。此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。
  • test:测试依赖范围,此依赖范围的Maven依赖,只对于测试的classpath有效,在项目编译主代码或者运行项目的使用时将无法使用此类依赖。
  • provided:已提供依赖范围,此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效,例如SpringBoot生成war包,其中的tomcat依赖就要是provided依赖范围,在开发中,就要改成compile依赖
  • runtime:运行时依赖范围,此依赖范围的Maven依赖,对于测试和运行有效,但在编译主代码时无效,典型的例子就是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口。
  • system:系统依赖范围,该依赖与三种classpath的关系,和provided依赖范围完全一致。但是使用system范围的依赖必须通过systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此要谨慎使用。systemPath可以引用环境变量,如:
<dependency>
    <groupId>javax.sql</groupId>
    <artifactId>jdbc-stdext</artifactId>
    <version>2.0</version>
    <scope>system</scope>
    <systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
  • import(Maven2.0.9及以上):导入依赖范围,该依赖范围不会对三种classpath产生实际的影响。

上述出import以外的各种依赖范围与三种classpath的关系表:

3:传递性依赖

一个基于SpringFramework的项目,如果不使用Maven,就要手动的去添加依赖包,通常是去官网下载,但是里面的依赖很多,会有不必要的依赖存在。另一种做法就是下载必要依赖包,但是这个包中不包含其他相关依赖,到实际使用的时候,根据报错引入相关依赖,这种做法是很麻烦的。

Maven的传递性依赖机制可以解决这个问题,例如:有一个spring-core的依赖,而在spring-core中也存在自己的依赖,包含了一个commons-logging依赖,见代码清单:

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
    <scope>compile</scope>
</dependency>

该依赖的依赖范围是compile。而spring-core的依赖范围也是cmpile,因此就会出现传递性依赖,使得项目也同时依赖commons-logging,如图所示

4:传递性依赖和依赖范围

针对上图的传递性依赖做一些解释

Maven project 依赖于 spring-core : 第一直接依赖

spring-core 依赖于 commons-logging :第二直接依赖

Maven project 对于 commons-logging:传递依赖

5:依赖调解

并不是所有的传递性依赖都能正常工作,当传递性依赖造成问题的时候,我们就需要清楚的知道该传递性依赖是从哪条依赖路径引入的。

例如:

  • 第一原则:路径最近者优先:

在项目A中存在这样的依赖。A –> B –> C –>X(1.0)、A –> D –> X(2.0),X是A的传递性依赖,但是这两条依赖路径上有两个版本的X,那么哪个X会被Maven解析使用呢?在Maven中采用路径最近者优先策略,因此,X(2.0)会被解析使用

  • 第二原则:第一声明者优先

在针对第一原则下路劲相同,版本不一致的缺陷下提出了第二原则,在项目A中存在这样的依赖关系。A –> B –> Y(1.0)、A –> C – > Y(1.0),Y的依赖路径都是2,从Maven2.0.9开始,为了避免构建对的不确定性,Maven使用了该原则,在依赖路径相等的情况下,在POM中依赖声明的顺序决定了谁会被解析使用,顺序最靠前的那个依赖优胜,如果B的依赖声明在C之前,那么Y(1.0)就会被解析使用。

6:可选依赖

时间: 07-06

Maven实战07_依赖的相关文章

[Maven实战](9)传递性依赖

了解Spring的朋友都知道,创建一个Spring Framework项目都需要依赖什么样的Jar包.如果不使用Maven,那么在项目中就需要手动下载相关的依赖.由于Spring Framework又会依赖与其他开源类库,因此实际中往往会下载Spring Framework的jar包,还的下载所有它依赖的其他jar包.这么做往往就引入了很多不必要的依赖.另一种做法是只下载Spring Framework的jar包,不包含其他的相关依赖,到实际使用的时候,再根据报错信息,或者查询相关文档,加入需要

[Maven实战](8)依赖配置与依赖范围

 1. 依赖配置 依赖基本配置: <project> <dependencies> <dependency> <groupId>...</groupId> <artifactId>...</artifactId> <version>...</version> <exclusions> <exclusion> <groupId>...</groupId>

Maven实战(六)依赖

我们项目中用到的jar包可以通过依赖的方式引入,构建项目的时候从Maven仓库下载即可. 1. 依赖配置    依赖可以声明如下: <project> ... <dependencies> <dependency> <groupId>group-a</groupId> <artifactId>artifact-a</artifactId> <version>1.0</version> <exc

《Maven实战》整理三:坐标和依赖

1.1 何为Maven坐标 正如之前所说的,Maven的一大功能就是管理项目依赖.为了能自动化地解析任何一个Java构件,Maven就必须将它们唯一标识,这就依赖管理的底层基础——坐标. 1.2 坐标详解 Maven坐标的元素包括:groupId,artifactId.version.packaging.classifier.先看一组坐标定义,如下: <groupId>org.sonatype.nexus</groupId> <artifactId>nexus-inde

Maven实战(十一)eclipse下载依赖jar包出问题

问题描述 在pom.xml中配置了依赖,但是提示依赖不成功,或在本地仓库找不到相关依赖 大致错误如下: ArtifactDescriptorException: Failed to read artifact descriptor for commons-beanutils:commons-beanutils-core:jar:1.8.0: ArtifactResolutionException: Could not transfer artifact commons-beanutils:com

Maven实战读书笔记(三):Maven依赖

3.1 依赖的配置 一个依赖声明可以包含下面元素: <dependencies> <dependency> <groupId></groupId> <artifactId></artifactId> <version></version> <type></type> <scope></scope> <optional></optional>

Maven实战之初识MavenMaven的简单介绍

Maven实战之初识MavenMaven的简单介绍 作用:Maven主要用于项目的构建,管理项目的依赖以及项目的信息(自动化构建.编译.单元测试.生成文档.打包.部署) 优势:相对于Ant.Make等,Maven抽象构建过程,提供构建任务的实现,自动化构建,有效地提高了开发效率,使开发人员可以集中精力在主要的开发任务上.而且Maven是跨平台工具,意味着在主流操作系统中,Maven都提供了对应的技术支持 使用注意:需要在JDK1.4及以上版本使用 Maven的安装下载地址:Maven下载地址,选

Maven实战:Maven生命周期

前言 之前有写过一篇文章Maven实战,介绍了Maven的一些基本概念,以及对于一个初学者而言的Maven基础知识,当时在我看来掌握了这些基本是够用的. 随着工作的深入,越来越感觉对于Maven的理解不够,很多时候使用Maven出了问题都无法很快地解决,因此打算深入地从搭建Maven工程开始学习一下Maven,这篇文章就将自己的学习历程记录下来和网友朋友们分享. 从搭建最简单的Maven项目开始 LZ使用的是MyEclipse,那么就是用MyEclipse搭建一个简单的Maven项目.第一步,n

Maven实战(四)——基于Maven的持续集成实践

Martin的<持续集成> 相信非常多读者和我一样.最早接触到持续集成的概念是来自Martin的著名文章<持续集成>.该文最早公布于2000年9月,之后在2006年进行了一次修订.它清晰地解释了持续集成的概念.并总结了10条实践,它们分别为: 仅仅维护一个源代码仓库 自己主动化构建 让构建自行測试 每人每天向主干提交代码 每次提交都应在持续集成机器上构建主干 保持高速的构建 在模拟生产环境中測试 让每一个人都能轻易获得最新的可运行文件 每一个人都能看到进度 自己主动化部署 原始文章