Maven 依赖范围和依赖传递详解

本文详细讲解了Maven的依赖配置,包括依赖范围(compile, test, provided, runtime, system)及其作用,依赖传递的默认机制,以及如何通过exclusions标签排除传递性依赖。同时介绍了dependencyManagement和dependencies的区别,帮助理解Maven如何管理与解决依赖冲突。" 113671210,10543778,Python gensim实现文档相似性,"['自然语言处理', '文本分析', '信息检索', 'Python库']
部署运行你感兴趣的模型镜像

Maven 依赖范围和依赖传递详解

18.10.8 松江图书馆

依赖基本配置

在pom.xml文件 根元素project下的 dependencies标签中,配置依赖信息,内可以包含多个 dependence元素,以声明多个依赖。每个依赖dependence标签都应该包含以下元素:

  1. groupId, artifactId, version : 依赖的基本坐标, 对于任何一个依赖来说,基本坐标是最重要的, Maven根据坐标才能找到需要的依赖。

这3个属性,可以理解成一个3维的x-y-z坐标,可以通过3个值,来确定一个库中维一个依赖

gooupId 可以理解成一个java的包名(java包名中默认以公司域名倒写),在对应的.m2仓库,它是一个可以有很多层的目录,以. 来进行目录分级

artifactID 可以理解是项目或模块的名称

version 表示不同的版本号

  1. type: 依赖的类型,大部分情况下不需要声明。 默认值为jar

  2. Scope: 依赖范围(compile,test,provided,runtime,system 五种状态)

  3. Optional:标记依赖是否可选

  4. exclusions: 用来排除传递性依赖 其中可配置多个exclusion标签,每个exclusion标签里面对应的有groupId, artifactId, version三项基本元素

example Code:

   <project>   

   
       <groupId>groupA</groupId>  
       <artifactId>artifactA</artifactId>  
       <version>1.0</version> 
       <type>jar<type>
       <scope>complie<scope> 
    
       <dependencies>  
              <dependency>  
                     <groupId>groupC</groupId>  
                     <artifactId>artifactC</artifactId>  
                     <version>1.0</version>  
              </dependency>  
              <dependency>  
                     <groupId>groupD</groupId>  
                     <artifactId>artifactD</artifactId>  
                     <version>1.0</version>  
              </dependency>  

                     <exclusions> 
                             <exclusion> 
                             <groupId>T</groupId> 
                             <artifactId>jartifactD</artifactId> 
                             </exclusion> 
 
                             <exclusion> 
                            <groupId>TS</groupId> 
                            <artifactId>asm</artifactId> 
                            </exclusion> 

                      </exclusions>
          
            </dependencies>  
         
    </project> 

依赖范围

  1. compile: 编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效

  2. system: 系统依赖范围。该依赖与编译、测试、运行三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围依赖时必须通过systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。

example code:


    <dependencies>
    <dependency>
      <groupId>sun.jdk</groupId>
      <artifactId>tools</artifactId>
      <version>1.5.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/../lib/tools.jar</systemPath>
    </dependency>
      </dependencies>
  1. provided: 已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复地引入一遍(如:servlet-api)。

  2. runtime: 运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。

  3. test: 测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此类依赖。典型的例子就是JUnit
    ,它只有在编译测试代码及运行测试的时候才需要。

依赖传递

maven默认依赖体制

maven引入的传递性依赖机制,一方面大大简化和方便了依赖声明,另一方面,大部分情况下我们只需要关心项目的直接依赖是什么,而不用考虑这些直接依赖会引入什么传递性依赖。但有时候,当传递性依赖造成问题的时候,我们就需要清楚地知道该传递性依赖是从哪条依赖路径引入的。

maven对于依赖相同的资源,默认会做出以下优化:

第一原则:以短路径长度为准

例如,项目A有这样的依赖关系 : A–>B–>C–>X(1.0)、A–>D–>X(2.0),X是A的传递性依赖,但是两条依赖路径上有两个版 本的X,那么哪个X会被maven解析使用呢?两个版本都被解析显然是不对的,因为那会造成依赖重复,因此必须选择一个。maven依赖调解的第一原则:路径最近者优先。该例中X(1.0)的路径长度为3,而X(2.0)的路径长度为2,因此X(2.0)会被解析使用。

第二原则:相同路径长度时,以pom中声明顺序先者为准

依赖调解第一原则不能解决所有问题,比如这样的依赖关系:A–>B–>Y(1.0),A–>C–>Y(2.0),Y(1.0)和Y(2.0)的依赖路径长度是一样的,都为2。那么到底谁会被解析使用呢?在maven2.0.8及之前的版本中,这是不确定的,但是maven2.0.9开始,为了尽可能避免构建的不确定性,maven定义了依赖调解的第二原则:第一声明者优先。在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用。顺序最靠前的那个依赖优胜。

2020.1.14 修改
关于第二条原则,有些歧义

对于在同一个pom文件中,如果引入同一jar包,但不同版本时,后者会覆盖前者,则以后者为准. (当然这种情况一般不会出现)

另外,还有一种解决冲突的办法: 版本锁定原则.

版本锁定原则

面对众多的依赖,版本锁定这一种方式不需要考虑依赖的路径、声明优化等因素,可以直接锁定所依赖jar包的版本,锁定后不会考虑声明顺序及路径。
主要是使用dependencyManageme’标签来是实现

下面以锁定Struts2、Spring、Hibernate版本为例:

       <properties>
		<spring.version>4.2.4.RELEASE</spring.version>
		<hibernate.version>5.0.7.Final</hibernate.version>
		<struts.version>2.3.24</struts.version>
	</properties>
 
	<!-- 锁定版本,struts2-2.3.24、spring4.2.4、hibernate5.0.7 -->
	<dependencyManagement>
		<dependencies>
		    <dependency>
			    <groupId>org.apache.struts</groupId>
			    <artifactId>struts2-core</artifactId>
			    <version>${struts.version}</version>
		    </dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context</artifactId>
				<version>${spring.version}</version>
			</dependency>
		    <dependency>
			    <groupId>org.hibernate</groupId>
			    <artifactId>hibernate-core</artifactId>
			    <version>${hibernate.version}</version>
		    </dependency>
        </dependencies>
    </dependencyManagement>

注意:在工程中锁定依赖的版本并不代表在工程中添加了依赖, 如果工程需要添加锁定版本的依赖则需要单独添加标签,依然需要使用dependencies标签来引入依赖,只是不必再指定版本号.

<dependencies>
    		    <dependency>
    			    <groupId>org.apache.struts</groupId>
    			    <artifactId>struts2-core</artifactId>
    			    <version>${struts.version}</version>
    		    </dependency>
</dependencise>

maven pom中配置 exclusion标签 手动去除依赖

场景: 比如,A 和 B 使用需都需要引用c jar包,A引用c的版本为1.0,B引用C的版本为2.0
原则上,我们使用最新版本作为支持,按照maven依赖系统默认原则,其实会引用的是C的1.0版本,此时我可以用exclusion来排除依赖

<dependencies>  
<dependency>  
<groupId>A</groupId>  
<artifactId>A</artifactId>  
<version>xxx</version>  
<exclusions>  
<exclusion>  
<groupId>C</groupId>  
<artifactId>C</artifactId> 
</exclusion>  
</exclusions>  
</dependency> 
 
<dependency>  
<groupId>B</groupId>  
<artifactId>B</artifactId>  
</dependency>  
</dependencies>  

dependencyManagement和dependencise的区别

dependencyManagement标签和denpendencise标签和可作为同级标签,也可作为上下级标签;

同级:dependencyManagement标签功能在于“申明”依赖,denpendencise标签在于“申明和使用”依赖

上下级: 因为dependencyManagement 申明一个依赖需要借助denpendencise标签,此时denpendencise标签为子标签

关于“申明”和“申明和使用”依赖的解释:

dependencyManagement标签申明依赖,主要功能为是版本version控制;

尤其在多模构建项目时,在统一的父模块中(父模块配置为<packaging>pom</packaging>),通过dependencyManagement标签,申明依赖,确认了依赖的版本version信息,子模块只需要通过denpendencise标签来引入依赖,不用指定版本,默认用的就是父类版本;
此时要注意: 子项目依赖父类没有申明的依赖,一定要加版本号,此时子类会仓库自行找对应的依赖信息;子项目依赖父类申明的依赖,version版本和父类不同,此时子类也会在仓库中找对应自己的依赖信息;


在这里插入图片描述

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值