Maven 坐标与依赖管理

1 中央仓库

Maven是从那里下载构件呢,其实maven内置了一个中央仓库的地址(http://repo1.maven.org/maven2),该中央仓库包含了世界上大部分流行的开源项目构件,Maven会在需要的时候去那里下载

Maven 坐标与依赖管理_第1张图片

2 maven坐标

Maven坐标为各种构件引入了秩序,任何一个构件都必须明确定义自己的坐标,而一组Maven坐标是通过一些元素定义的,它们是groupId、artifactId、version、packing、classifier。下面是一组坐标的定义:

org.sonatype.nexus
nexus-indexer
2.0.0
jar

下面解释一下各个坐标的元素:

groupId:定义当前maven项目隶属的实际项目,例如SpringFramework这一实际项目,其对应的maven项目会有spring-core、spring-context、spring-aop等等,这就是Maven中模块的概念,一个实际的项目往往会划分为许多的模块。

artifactId: 表示实际项目中一个Maven项目模块

version: 表示Maven项目当前所处的版本

packaging: 表示Maven项目的打包方式

classifier: 用来帮助定义构建输出的一些附属构件,例如pac.plugin-2.0.0.jar是主构建,pac.plugin-2.0.0-javadoc.jar和pac.plugin-2.0.0-sources.jar是附属构件。

项目构件的文件名是与坐标相对应的,一般的规则为artifactId-version[-classifier].packing,[-classifier]表示可选。比如nexus-indexer的主构件为nexus-indexer-2.0.0.jar,附属构件有nexus-indexer-2.0.0-javadoc.jar。这里还要强调的一点是,packaging并非一定与构件扩展名对应,比如packaging为maven-plugin的构件扩展名为jar。

3依赖

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


   
	
	     
	     
	     
	      依赖类型,默认为jar
	      依赖范围【compiler、test、provided、runtime、system】
	      标记依赖是否可选
	      用来排除传递性依赖
	        
		    ……………
                
	        
                     ……………
               
	    
        
  

3.1 依赖范围

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

test: 测试依赖范围。只对测试classpath有效

provided: 已提供依赖范围。对编译和测试classpath有效,运行时无效

runtime: 运行时依赖范围。对测试和运行classpath有效,编译主代码时无效

system:系统依赖范围。和provided依赖范围完全一致。但是使用system范围的依赖是必须通过systemPath元素显示地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往与本机系统绑定,可能造成构建的不可移植,因此应该少用。

import:导入依赖范围,不会对三种classPath产生实际的影响。

下图是依赖范围与classPath的关系:

Maven 坐标与依赖管理_第2张图片

依赖范围与classPath的关系

3.2 传递性依赖

account-email有一个compiler范围的spring-core依赖,spring-core有一个compiler范围的commons-logging依赖,那么commons-logging就会成为account-email的compiler范围的依赖,commons-logging是account-email的一个传递依赖,如下图所示:

传递性依赖图

依赖范围不仅可以控制与三种classpath的关系,还对传递性依赖产生影响。假设A依赖于B,B依赖于C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖的范围和第二直接依赖范围决定了传递性依赖的范围,如下图所示:最左边一列表示第一直接依赖,最上面一行表示第二直接依赖,中间的交叉单元格则表示传递性依赖范围。

Maven 坐标与依赖管理_第3张图片
依赖范围影响传递性依赖
3.3 依赖调解

从上图中,我们可以看出:当第二直接依赖范围是compiler的时候,传递性依赖的范围与和一直接依赖的范围一致;当第二直接依赖的范围是test的时候,依赖不会得到传递;当第二直接依赖范围是provide的时候,只传递第一直接依赖为provide的依赖,且传递的依赖范围也为provide;当第二直接依赖范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compiler例外,此传递性依赖范围为runtime。

短路径和第一声明优先的原则:

项目A有这样的依赖关系:A->B->C->X(1.0)和A->D->X(2.0),X为A的传递性依赖,Maven会选择那个版本的X呢,Maven的调解的第一原则是:短路径最近者优先,X(1.0)的路径长度为3,X(2.0)的路径长度为2,因此会选择X(2.0)。

依赖调解的第二原则是第一声明优先的原则:

比如有这样的一种依赖关系:A->B->Y(1.0),A->C->Y(2.0),两种情况下Y的依赖路径是一样的,均为2,根据第一声明优先的原则,在POM中依赖声明的顺序决定了谁会被解析使用,顺序最靠前的那个依赖优先,在该例中,如果B的依声明在C之前,那么Y(1.0)会被解析。

3.4 可选依赖

假设有这样一个依赖关系,项目A依赖于项目于B,项目B依赖于项目X和Y,B于X和Y的依赖都是可选的:A->B, B->X(可选),B->Y(可选)。根据传递依赖的定义,如果这三个依赖的范围均是compiler,那么X、Y就是A的compiler范围传递性依赖。然而,由于这里X、Y是可选的,依赖不会得以传递。换句话说,X、Y将不会对A有任何影响,如下图所示:


Maven 坐标与依赖管理_第4张图片

可选依赖

为什么要使用可选择依赖这一特性呢?可能项目B实现了两个特性,其中的特性一依赖于X,特征二依赖于Y,而且这两个特征是互斥的,用户不可能同时使用两个特征。比如B是一个持久层隔离工具包,它支持多种数据库,包括MySQL, PostgreSQL等,在构建这个工具包的时候,需要这两种数据库的驱动程序,但在使用这个工具包的时候,只会依赖一种数据库。项目B的依赖声明见如下代码清单:


     4.0.0
      com.juvenxu.mvnbook < /groupId>
     project-b 
     1.0.0
     
	
	    mysql
	    mysql-connector-java
	    5.1.10
	    true
        
	
           postgresql
	    postgresql 
	   8.4-701.jdb3
	   true
	
    

上述XML片段中,使用元素表示mysql-connector-java和postgresql这两个依赖为可选依赖,它们只会对当前项目B产生影响,当其它项目依赖于B的时候,这两个依赖不会被传递。因此, 当项目 A 依赖项目 B 的时候,如果其实际使用基于 Mysql 数据库,那么就可以在 A 中显示地声明 mysql-connector-java 这一依赖

3.5 排除依赖

  


    4.0.0
     com.juvenxu.mvnbook < /groupId>
    project-a 
    1.0.0
    
	
	     com.juvenxu.mvnbook 
	    project-b
	    1.0.0
	    
		 
		     com.juvenxu.mvnbook 
		    project-c
		 
	   
	
	
              com.juvenxu.mvnbook 
	     project-c
	     1.1.0
	
    

上述代码中,项目A依赖于项目B,但是由于一些原因,不想引入传递性依赖C,而是自己显式声明对于项目C 1.1.0版本的依赖。代码中使用了exclusions元素声明排除依赖。需要注意的是,声明exclusion的时候只需要groupId和artifactId,而不需要version元素,这是因为groupId和artifactId就能唯一定位依赖图中的某个依赖,换句话说,Maven解析后依赖中,不可能出现groupId和artifactId相同,但是version不同的两个依赖。
 排除依赖

3.6归类依赖

同一个项目中有很多关于Spring Framework的依赖,这些依赖的模块是来自同一个项目不同的模块,所有这些依赖的版本都是相同的,而且是可预见的,如果要升级,一起升级就可以了,用如下的方法可以解决这个问题就这就是归类依赖:

         
		4.0.0
		 com.juvenxu.mvnbook < /groupId>
		project-b 
		1.0.0

		
			2.5.6
				
		
		
			
				org.springframework
				spring-core 
				${springframework.version}
			
			
				org.springframework
				spring-beans 
				${springframework.version}
			
                        
				org.springframework
				spring-context 
				${springframework.version}
			
                        
				org.springframework
				spring-context-support /artifactId>
				${springframework.version}
			
	     
      

3.7 优化依赖

mvn dependency:list 查看当前项目的已解析的依赖

Maven 坐标与依赖管理_第5张图片
已经解析的依赖列表

mvn dependency:tree 查看当前项目的依赖树

Maven 坐标与依赖管理_第6张图片
已解析的依赖树

mvn dependency:ananyze 查看当前项目的依赖分析

Maven 坐标与依赖管理_第7张图片
使用但未声明的依赖与声明但未使用的依赖

你可能感兴趣的:(Maven 坐标与依赖管理)