`

三. 坐标和依赖

 
阅读更多

1. 何为Maven坐标

    Maven定义了这样一组规范:世界上任何一个构件都可以使用Maven坐标唯一标识;

    Maven坐标包括groupId、atrifactId、version、packaging、classifier。

groupId:必须,定义当前Maven项目隶属的实际项目;

atrifactId:必须,定义实际项目中的一个Maven项目(模块),推荐的做法是使用实际项目名称作为atrifactId的前缀。

version:必须,定义Maven项目当前所处的版本。

packaging:可选(默认jar),定义Maven项目的打包方式。

classifier:不能直接定义,帮助定义构建输出一些附属构建,附属构建于主构件对应。

Maven内置了一个中央仓库的地址(http://repo.maven.apache.org/maven2),Maven仓库的布局也是基于Maven坐标

 

2.基于一个account-email的POM

(1)首先看一下该模块的POM

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.gqshao.myapp.account</groupId>
	<artifactId>account-email</artifactId>
	<name>Account Email</name>
	<version>1.0.0-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>2.5.6</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>2.5.6</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>2.5.6</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>2.5.6</version>
		</dependency>
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>1.4.1</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.icegreen</groupId>
			<artifactId>greenmail</artifactId>
			<version>1.3.1b</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<!-- 使用-source5或更高版本以启动注释插件(apache-maven-3.0.5没用上) -->
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-resources-plugin</artifactId>
				<configuration>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

    该项目坐标:groupId:com.gqshao.myapp.account;artifactId:account-email;version:1.0.0-SNAPSHOT

    由于该模块属于账户注册服务项目的一部分,因此,其groupId对应了account项目。该模块的artifactId仍然以account作为前缀,以方便区分其他项目的构建。最后1.0.0-SNAPSHOT表示该版本仍在开发中。

    再看dependencies元素,其中包含了多个dependency子元素,这是POM中定义项目依赖的位置。

    以第一个依赖为例groupId:org.springframework;artifactId:spring-core;version:2.5.6。这便是依赖坐标,任何一个Maven项目都需要定义自己的坐标,当这个Maven项目成为其他Maven项目的依赖的时候,这组坐标就体现了价值。spring-core、spring-beans、spring-context、spring-context-support是Spring Framework实现依赖注入等功能必要的构件。

    在spring-context-support之后有一个javax.mail;mail;1.4.1,是实现发送必须的类库。

    紧接着是junit;junit;4.7,是单元测试,这个依赖特殊的地方在于一个值为test的scope子元素,scope用来定义依赖范围。

    随后的依赖是com.icegreen;greenmail;1.3.1b是开源邮件服务测试套件。

    plugin org.apache.maven.plugins 是开启Java5的支持。

 

(2)account-email主代码

    项目主代码位于src/main/java,资源文件(非Java)位于src/main/resources目录下

    配置文件在src/main/resources/account-email.xml中

 

(3)account-email的测试代码

    测试相关的Java代码位于src/test/java目录,相关的资源文件则位于src/test/resources目录

    运行mvn clean test执行测试

 

3.构建account-email

    使用mvn clean install构建account-email,Maven会根据POM配置自动下载所需要的依赖构建,执行编译、测试、打包等工作,最后将项目生成的构建account-email-1.0.0-SNAPSHOT.jar安装到本地仓库中。这时,该模块就能供其他Maven项目使用了。

 

4.依赖的配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	...
	<dependencies>
		<dependency>
			<groupId>...</groupId>
			<artifactId>...</artifactId>
			<version>...</version>
			<type>...</type>
			<scope>...</scope>
			<optional>...</optional>
			<exclusions>
				<exclusion>
				...
				</exclusion>
			</exclusions>
		</dependency>
		...
	</dependencies>
...
</project>

    根元素project下的dependencies可以包含一个或多个dependency元素,以声明一个或多个项目依赖。

每个依赖可以包含的元素有:

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

type:依赖的类型,对应于项目坐标定义的packaging。大部分情况下,该元素不必声明,其默认值为jar

scope:依赖的范围

optional:标记依赖是否可选

exclusions:用来排除传递性依赖

大部分情况下依赖声明只包含基本坐标,然而在一些特殊情况下,其他元素至关重要

 

5.依赖范围

    Maven在编辑项目主代码的时候需要使用一套classpath

比如:

    编译classpath:项目主代码需要用到spring-core,该文件以依赖的方式被引入到classpath中。

    测试classpath:当Maven在编译和执行测试的时候会使用另外一套classpath,JUnit以依赖的方式引入到测试使用的classpath中,这里的依赖范围是test。

    运行classpath:实际运行Maven项目的时候,又会使用一套classpath,上例中的spring-core需要在该classpath中,而JUnit则不需要。

    依赖范围就是用来控制这三种classpath(编译、测试、运行classpath)

 

Maven依赖范围有如下几种:

    compile:编译依赖范围(默认)。对于编译、测试、运行三种classpath都有效。比如spring-core

    test:测试依赖范围。使用此依赖范围的Maven依赖,只对测试classpath有效。在编译主代码或者运行项目的时候使用时将无法使用此类依赖。比如JUnit。

    provided:已提供依赖范围。使用此依赖范围的Maven依赖,只对编译和测试classpath有效。但在运行时无效。比如servlet-api

    runtime:运行时依赖范围。使用此依赖范围的Maven依赖,只对测试和运行时classpath有效。但在编译主代码时无效。比如JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口。

    system:系统依赖范围,和provided依赖范围一致。但是,必须通过systemPath元素显示的指定依赖路径。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:导入依赖范围,该依赖范围不会对三种classpath产生时间影响,该依赖范围只有在dependencyManagement元素下才有效果,使用该范围的依赖通常指向一个POM,作用是将该POM目标中的dependencyManagement合并到当前POM的dependencyManagement中。即在另一个模块中使用与另一个项目完全一样的dependencyManagement,除了复制配置或者继承这两种方式外,还可以考虑import范围依赖将这一配置导入。

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-framework-bom</artifactId>
			<version>${spring.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

 

 

 

依赖范围对三种classpath的影响

依赖范围(scope) 编译classpath有效 测试classpath 运行时classpath 例子
compile Y Y Y spring-core
test Y JUnit
provided Y Y servlet-api、jsp-api
runtime Y Y JDBC驱动实现、连接池
system Y Y 本地Maven仓库之外的类库文件

 

6.传递性依赖

(1)何为传递性依赖

    背景:一个基于Spring Framework的项目,如果不使用Maven,那么在项目中就需要手动下载相关依赖。由于Spring Framework又会依赖其它开源类库,因此实际中往往会下载一个很大的如spring-framework-2.5.6-with-dependencies.zip的包,包含了所有Spring Framework的jar包,以及所有它依赖的其它jar包。另一种做法是只下载spring-framework-2.5.6.zip,到实际使用的时候,再根据出错信息,或者查询相关文档,加入需要的其他依赖。

    Maven的传递性依赖机制可以很好的解决这一问题。以account-email项目为例,该项目有一个org.springframework:spring-core:2.5.6的依赖,而实际上spring-core也有它自己的依赖,可以看到http://repo1.maven.org/maven2/org/springframework/spring-core/2.5.6/spring-core-2.5.6.pom中(可通过http://repo.maven.apache.org/maven2/ --- http://search.maven.org --- 搜索spring找到)可以看到如下信息:

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

    该依赖没有声明依赖范围,那么就是默认的compile。spring-core的依赖范围也是compile。

    即在account-email中有一个compile范围的spring-core依赖,spring-core有一个compile范围的commons-logging,那么commons-logging就会成为account-email的compile范围依赖。有了传递性依赖机制,在使用Spring Framework的时候就不用去考虑它依赖了什么,也不用担心引入多余的依赖,Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中。

 

(2)传递性依赖和依赖范围

    依赖范围不仅可以控制依赖与三种classpath的关系,还对传递性依赖产生影响

下面表格中第一列表示第一直接依赖范围,最上面表示第二直接依赖范围,中间交叉的单元格则表示传递性依赖范围

  2:compile 2:test 2:provided 2:runtime
1:compile compile runtime
1:test test test
1:provided provided provided provided
1:runtime runtime runtime

 

 

7.依赖调节

    背景:Maven引入的传递性依赖,简化了依赖声明。但有时候也会造成问题。

    比如项目A有如下两个依赖关系 A→B→C→X(1.0) 和 A→D→X(2.0)。在这两个依赖关系中X都是A的传递性依赖,但是两条依赖路径上有两个版本的X,由于两个版本都解析会造成依赖重复,那么那个版本的X会被Maven解析使用

    Maven依赖调节(Dependcy Mediation)的第一原则:路径最近者优先。上例中X(1.0)路径长度为3,X(2.0)路径长度为2,因此X(2.0)会被解析使用。

    Maven依赖调节(Dependcy Mediation)的第二原则:第一声明者优先。

 

8.可选依赖

    背景:假设有这样一个依赖关系,项目A依赖于项目B,项目B依赖于项目X和Y,B对于X和Y都是可选依赖:A→B、B→X(可选),B→Y(可选),那么,X和Y就是A的compile范围传递性依赖。但是X和Y是可选依赖,依赖将不会传递,也就是X和Y将不会对A有任何影响。

    使用可选依赖的原因:B实现了两个特性,其中一个特性依赖于X,另一个特性依赖于Y,而且这两个特性是互斥的,用户不可能同时使用两个特性。比如B是一个持久层隔离工具包,支持多种数据库,包括Oracle、MySql等。

    使用<optional>表示为可选依赖,它们只会对B项目产生影响,当其他项目依赖于B的时候,这两个依赖不会被传递。因此,当项目A依赖于B的时候,需要显示的声明X或Y这一依赖。

 

9.最佳实践

(1)排除依赖

    背景:情况一,由于传递性依赖的原因,项目依赖了一个SNAPSHOT版本;情况二,有些类库不在中央仓库中。这两种情况下都需要排除依赖性传递,在声明一个稳定版本或可以替换的版本。

例子: A依赖B,B依赖C,此时不想引入传递性C,并显示声明自己对于项目C的依赖。

<project>
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.gqshao.myapp</groupId>
	<artifactId>project-a</artifactId>
	<version>1.0.0</version>
	<dependencies>
		<dependency>
			<groupId>com.gqshao.myapp</groupId>
			<artifactId>project-b</artifactId>
			<version>1.0.0</version>
			<exclusions>
				<exclusion>
					<groupId>com.gqshao.myapp</groupId>
					<artifactId>project-c</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>com.gqshao.myapp</groupId>
			<artifactId>project-c</artifactId>
			<version>1.1.0</version>
		</dependency>
	</dependencies>
</project>

    exclusions:可以包含多个exclusion元素,因此可以排除一个或者多个传递性依赖。

    exclusion:声明exclusion只需要groupId和artifactId,而不需要version元素。这是因为只需要groupId和artifactId就能唯一定位依赖图中的某个依赖。也就是说Maven解析后的依赖中,不可能出现groupId和artifactId相同,但是version不同的两个依赖。

 

(2)归类依赖

    背景:有很多关于Spring Framework的依赖,来自同一个项目不同的模块,因此这些依赖的版本都是相同的。如果将来需要升级Spring Framework,这些依赖的版本会一起升级。

解决方法:Maven的属性,通过properties元素定义Maven属性,Maven会将所有${属性名}替换成实际值。

<?xml version="1.0" encoding="UTF-8"?>
<project>
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.gqshao.myapp</groupId>
	<artifactId>project-a</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)优化依赖

    背景:在软件开发中,程序员会通过重构等不同方式不断优化自己的代码,同理,程序员也应该对Maven项目的依赖了然于胸,并对其进行优化,如去除多余的依赖,显示的声明某些必要的依赖。

Maven会自动解析所有直接依赖和传递性依赖,并根据规则正确判断每个依赖的范围。对一些依赖冲突也能进行调节,确保任何一个构件只有唯一的版本在依赖中存在,在这个工作之后得到的那些依赖被称为已解析依赖(Resovled Dependency),

运行下面命令查看当前项目已解析依赖:

mvn dependency:list

 

如果要显示树状结构通过下面命令

mvn dependency:tree

 

显示使用但未声明的依赖与声明但未使用的依赖(由于内容太多,输出到文件)

mvn dependency:analyze >c:\analyze.txt

   

下载所有的依赖

mvn dependency:copy-dependencies -DoutputDirectory=./src/main/webapp/WEB-INF/lib

 

 

 

    结果分成两个部分Used undeclared dependencies(项目中使用到,但未显示声明)和Unused declared dependencies(项目中未使用,但显示声明的依赖)

注意:由于 dependency:analyze 只会分析编译主代码和测试代码所用到的依赖,一些执行测试和运行时需要的依赖发现不了,所以Unused declared dependencies要根据实际情况分析。

 

 

10.向私库中添加中央仓库没有的依赖

例如:oracle jdbc driver

(1)从官网下载jdbc driver,放在D:\下

(2)执行命令进安装

mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.1.0 -Dpackaging=jar -Dfile=ojdbc6.jar

    此时在~\.m2\repository\oracle\ojdbc6\11.2.0.1.0下可以看到ojdbc6.jar文件

(3)POM中添加如下依赖信息

<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc6</artifactId>
    <version>11.2.0.1.0</version>
</dependency>

 

或根据项目添加

mvn dependency:copy-dependencies

 

分享到:
评论

相关推荐

    org.json.JSONObject引用依赖包

    `org.json.JSONObject`是`org.json`包下的主要类,通常包含在`json.jar`这样的依赖包中。 `JSONObject`类提供了丰富的API,如`put()`、`get()`、`opt()`等,允许我们创建、读取和修改JSON对象。例如,我们可以使用`...

    根据pom.xml下载依赖

    每一项依赖都有其groupId、artifactId、version三个关键属性,这三者共同构成了一个唯一的坐标,Maven会根据这个坐标在Maven中央仓库或其他指定的远程仓库中查找并下载相应的jar包。 例如,一个简单的pom.xml文件中...

    pdfdemo2-master_pdf.js坐标点_加工_pdf关键字坐标获取_

    它提供了API,使得开发者可以轻松地处理PDF文档的各种任务,包括解析PDF元数据、渲染页面、以及获取文本和图形元素的坐标信息。 在这个项目中,首先需要理解PDF文档的结构。PDF文档由一系列的对象组成,包括页、...

    lzugis.zip_DEMO_Geotools_com.lzugis_lzudb.com_坐标转换 shp

    这个DEMO是学习和理解GeoTools库的强大资源,它涵盖了GIS开发的基本操作,如Shapefile的生成与操作,数据格式转换,以及坐标转换。对于任何想涉足GIS开发或者利用GeoTools进行地图数据处理的开发者来说,这是一个极...

    echarts-gl.js和echarts-gl.main.js依赖包

    6. **坐标系统**:ECharts-gl 提供了适用于三维场景的坐标系统,包括笛卡尔坐标系和地理坐标系。这使得开发者能够在地球上或者其他三维空间中精确地定位和展示数据。 7. **自定义几何体**:除了预设的图形,ECharts...

    万维坐标转换工具万维坐标转换工具万维坐标转换工具

    3. 参数模型:坐标转换往往依赖于一定的数学模型,如七参数法(三个平移参数、三个旋转参数和一个尺度参数)、三参数法(两个平移参数和一个尺度参数)或四参数法。这些参数通常由已知控制点的坐标来确定,以确保...

    EPNP根据像素坐标求解实际三维世界坐标python实现

    EPNP(Efficient Perspective-n-Point)算法是一种在计算机视觉领域广泛应用的方法,主要用于从二维图像中的像素坐标恢复三维场景的几何信息。这个Python实现是基于该算法,它可以帮助我们从多个视图的二维图像中...

    xy.zip_xy大地坐标转换经纬度_坐标 转换_坐标转换_经纬度 坐标

    首先,大地坐标系统(也称为地心地固坐标系统)是一种基于地球椭球体模型的三维坐标系统,通常用经度、纬度和海拔高度来表示地理位置。经纬度坐标系统是另一种常见的地理坐标系统,由经度和纬度来标识地球上任何位置...

    geotools依赖包

    3. 投影转换:支持地理坐标系与投影坐标系之间的转换,这对于跨地区的数据分析和展示至关重要。 4. 地图渲染:提供了地图符号化和渲染的能力,可以将地理数据转换为可视化地图。 5. SQL查询:支持标准的SQL-92查询...

    C#绘制坐标轴 C#绘制坐标轴 C#绘制坐标轴

    在WPF中,我们可以使用`System.Windows.Shapes`和`System.Windows.Media`命名空间,其中`Path`、`Line`、`TextBlock`等元素可以用来绘制坐标轴。WPF的绘制方式更偏向于声明式,通过XML样式的XAML来布局和定义图形。...

    三个角点坐标绘制矩形的算法研究

    在地形测量和地理信息系统(GIS)等测绘领域中,准确地从有限的三个角点坐标绘制出矩形是一个常见且实际的问题。由于实际测量中可能由于各种条件限制,只能获得矩形三个角点的坐标,这时如何确定第四个角点的位置并...

    GPS坐标转换为百度地图坐标(JS)

    在IT行业中,尤其是在地理信息系统(GIS)领域,坐标转换是一个重要的环节。GPS(全球定位系统)使用的是WGS84坐标系,而国内常见的百度地图则使用的是BD09坐标系。由于这两种坐标系的不同,当我们在GPS设备上获取到...

    geotools依赖.rar

    在“geotools依赖.rar”这个压缩包中,最核心的部分很可能是“repository”文件夹,这通常包含了GeoTools项目所需要的各种外部库的JAR文件。这些JAR文件是Maven仓库的一部分,用于构建和运行GeoTools项目。 在Geo...

    七参数坐标转换Java语言代码

    这些参数的确定通常依赖于已知对应点在两个坐标系中的坐标。 在大地坐标系中,坐标通常表示为经纬度和海拔高度,而空间直角坐标系则使用笛卡尔坐标(X、Y、Z)。转换过程通常包括以下步骤: 1. **参数预处理**:...

    CAD功能在三坐标测量机中的应用.pdf

    脱机编程是提高三坐标测量机工作效率的重要手段,它可以解决传统编程方法中对硬件环境和工件依赖的问题。通过引入CAD功能,可以在不依赖实际工件的情况下完成测量程序的编制。这意味着编程可以提前进行,而不必等到...

    坐标系之间的坐标转换.pdf

    莫洛金斯基模型则适用于地心坐标系之间的转换,它基于三次多项式进行坐标平移、旋转和缩放。 此外,还有其他坐标转换模型,如武测模型,适用于特定的地理环境和测量需求。这些模型的选择和应用依赖于具体任务的复杂...

    osgb坐标系设置1

    【osgb坐标系设置1】涉及的是在IT领域中,特别是3D可视化和地理信息系统(GIS)中的一个重要概念——OSGB(Ordnance Survey Great Britain)坐标系统以及如何使用特定工具进行转换和设置。OSGB是英国国家地理空间...

    OpenGL中关于坐标使用常见问题的分析

    在OpenGL中,坐标单位的选择依赖于具体的应用场景和需求。对于对象坐标,单位可以是任意的,通常由开发者根据场景尺度自行设定。然而,在屏幕坐标系统中,坐标单位受到显示设备的物理尺寸和分辨率的影响,通常是像素...

Global site tag (gtag.js) - Google Analytics