Maven 坐标与依赖管理

1 中央仓库

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


2 maven坐标

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

<groupId>org.sonatype.nexus</groupId>
<artifactId>nexus-indexer</artifactId>
<version>2.0.0</version>
<packing>jar</packing>

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

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依赖

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

<project>
   <dependencies>
	<dependency>
	     <groupId>…<groupId>
	     <artifactId>…</artifactId>
	     <version>…</version>
	     <type>…</type> 依赖类型,默认为jar
	     <scope>…</scope> 依赖范围【compiler、test、provided、runtime、system】
	     <optional>…</optional> 标记依赖是否可选
	     <exclusions> 用来排除传递性依赖
	        <exclusion>
		    ……………
                </exclusion>
	        <exclusion>
                     ……………
               </exclusion>
	    </exclusions>
        </dependency>
  </dependencies>
</project>

3.1 依赖范围

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

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

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

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

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

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

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


依赖范围与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是传递性依赖。第一直接依赖的范围和第二直接依赖范围决定了传递性依赖的范围,如下图所示:最左边一列表示第一直接依赖,最上面一行表示第二直接依赖,中间的交叉单元格则表示传递性依赖范围。


依赖范围影响传递性依赖
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有任何影响,如下图所示:



可选依赖

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

<project>
     <modelVersion>4.0.0</modelVersion>
     <groupId> com.juvenxu.mvnbook < /groupId>
     <artifactId>project-b </artifactId>
     <version>1.0.0</version>
     <dependencies>
	<dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	    <version>5.1.10</version>
	    <optional>true</optional>
        </dependency>
	<dependency>
           <groupId>postgresql</groupId>
	   <artifactId> postgresql </artifactId>
	   <version>8.4-701.jdb3</version>
	   <optional>true</optional>
	</dependency>
    </dependencies>
</project>
上述XML片段中,使用<optional>元素表示mysql-connector-java和postgresql这两个依赖为可选依赖,它们只会对当前项目B产生影响,当其它项目依赖于B的时候,这两个依赖不会被传递。因此, 当项目 A 依赖项目 B 的时候,如果其实际使用基于 Mysql 数据库,那么就可以在 A 中显示地声明 mysql-connector-java 这一依赖

3.5 排除依赖

  

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

 排除依赖

3.6归类依赖

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

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

		<properties>
			<springframework.version>2.5.6</ springframework.version>
		</properties>		
		
		<dependencies>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-core </artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-beans </artifactId>
				<version>${springframework.version}</version>
			</dependency>
                        <dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context </artifactId>
				<version>${springframework.version}</version>
			</dependency>
                        <dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context-support /artifactId>
				<version>${springframework.version}</version>
			</dependency>
	     </dependencies>
      </project>

3.7 优化依赖

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

已经解析的依赖列表

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

已解析的依赖树

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

使用但未声明的依赖与声明但未使用的依赖
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值