Maven学习笔记(四):坐标与依赖

Maven坐标详解:

Maven定义了这样一组规则:世界上任何一个构件都可以使用Maven坐标唯一标识,Maven坐标的元素包括groupId、artifactId、version、packaging、classifier。我们只需要提供正确的坐标元素,Maven就能找到对应的构件。比如当需要使用Java5平台上的TestNG的5.8版本时,就告诉Maven:”groupId=org.testng;
artifactId=testng; version=5.8; classifer=jdk15,maven就会从中央仓库(http://search.maven.org/#browse)中寻找相应的构件供我们使用。

先看一组坐标定义,如下:

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

nexus-indexer是一个对Maven仓库编纂索引并提供搜索功能的类库,它是Nexus项目中的一个子模块。后面会详细介绍Nexus。下面详细解释一下各个坐标元素:

     groupId:定义当前Maven项目隶属的实际项目。首先,Maven项目和实际项目不一定是一对一的关系,比如SpringFramework这一实际项目,其对应的Maven项目会有很多,如spring-core、spring-context等。一个实际项目通常会划分成多个项目模块。groupId不应该只对应于项目隶属的组织或公司,原因是一个组织下会有很多实际项目,如果groupId只定义到组织级别,后面可以看到,artifactId只能对应Maven项目,那么实际项目这个层将难以定义。最后,groupId的表示方式与java包名的表示方式类似,通常与域名反向一一对应。

artifactId:该元素定义了实际项目中的一个Maven项目(模块),推荐的做法是使用实际项目名称作为artifactId的前缀。比如上例的artifactId是nexus-indexer,使用了实际项目名nexus作为前缀,这样做的好处是方便寻找实际构件。

version:该元素定义了Maven项目当前所处的版本。实际上,Maven定义了一套完整的版本规范,以及快照(SNAPSHOT)的概念。在后面的章节将详细讨论。

     packaging:该元素定义Maven项目的打包方式。首先,打包方式通常与所生成构件的文件扩展名对应,如上例中packaging为jar,最终的文件名为nexus-indexer-2.0.0.jar。而是用war打包方式的Maven项目,最终生成的构件会有一个.war文件,但这不是绝对的。当不定义packaging时,Maven会是用默认值jar。

classifier:该元素用来帮助定义构件输出的一些附属构件。附属构件与主构件对应。如上例中的主构件是nexus-indexer-2.0.0.jar,该项目还会通过一些插件生成如nexus-indexer-2.0.0-javadoc.jar、nexus-indexer-2.0.0-sources.jar这样一些附属构件,其包含了Java文档和源代码。这时候,javadoc和sources就是这两个附属构件的classifier。这样,附属构件也就拥有了自己唯一的坐标。注意:不能直接定义项目的classifier,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成。

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

依赖的配置:

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

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

根元素project下的dependencies可以包含一个或者多个denpendency元素,以声明一个或者多个项目依赖。每个依赖可以包含的元素有:

  • groupId、artifactId和version:依赖的基本坐标,对于任何一个依赖来说,基本坐标是最重要的,Maven根据坐标才能找到需要的依赖。
  • type:依赖的类型,对应于项目坐标定义的packaging。大部分情况下,该元素不必声明,其默认值为jar。
  • scope:依赖的范围,请见后面小节
  • optional:标记依赖是否可选,请见后面小节
  • exclusions:用来排除传递性依赖,请见后面小节

Maven依赖范围:

在Maven中,依赖范围用元素scope表示。Maven在执行编译、测试、运行时执行的是三套不同的classpath。

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

 compile:编译依赖范围。如果没有指定,就会默认使用该依赖范围。该此依赖范围对于编译、测试、运行三种classpath都有效。典型的例子是spring-core,在编译、测试和运行的时候都需要使用该依赖。

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

provided:已提供依赖范围。该依赖范围对于测试和运行class-path有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复引入一遍。

     runtime:运行时依赖范围。该范围依赖,对于运行和测试class-path有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体的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: 导入依赖范围。该依赖范围不会对三种classPath产生实际的影响,我们将在后面的章节详细介绍该依赖。

传递性依赖:

何为传递性依赖:

传递性性依赖的意思是项目A依赖了B构件,而在B构件的pom.xml中又显式的依赖了C构件,那么A项目也就会依赖到C构件。在不使用Maven的项目当中,我们通常需要手动的去寻找所有直接使用和间接使用的构件(传递性依赖),以及解决版本冲突的问题,这将耗费很大的精力且意义不大。

Maven的传递性依赖机制可以很好的解决这一问题。在A项目下有一个org.springframework:spring-core:2.5.6的依赖,而实际上spring-core也有它自己的依赖,例如spring-core-2.5.6.pom该文件包含了一个commos-logging依赖,见下面代码:

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

commons-logging没有声明依赖范围,那么其依赖范围就是默认的compile,而spring-core一般的依赖范围也是compile。

A项目有一个compile范围的spring-core依赖,spring-core有一个compile范围的commons-logging依赖,那么commons-logging就会成为A项目的compile范围依赖,commons-logging是account-email的一个传递性依赖。

有了传递性依赖机制,在使用Spring Framework的时候就不用去考虑它依赖了什么,也不用担心引入多于的依赖。Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目之中。

传递性依赖和依赖范围:

假设A依赖与B,B依赖与C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围。如下表所示,最左边一列表示第一直接依赖范围,最上面一行表示第二直接依赖范围,中间的交叉单元格则表示传递性依赖范围。

  compile test provided runtime
compile compile     -         - runtime
test test     -         - test
provided provided     -         - provided
runtime runtime     -         - runtime

仔细观察该表,可以发现如下的规律:当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;当第二直接依赖的范围是test的时候,依赖不会得以传递;当第二直接依赖的范围是provided的时候,只传递第一直接依赖范围也为provided的依赖,且传递性依赖的范围同样为provided;当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compile例外,此时传递性依赖的范围为runtime。

时间: 2024-10-19 20:35:08

Maven学习笔记(四):坐标与依赖的相关文章

Maven学习笔记之——坐标和依赖(上)

Maven学习笔记之--坐标和依赖(上) 1.    Maven坐标概念 Maven通过构件的坐标来在Maven仓库中定位到具体的构件.Maven的坐标元素包括groupId.artifactId.versiion.packaging.classifier.Maven内置了一个中央仓库地址.需要时Maven会根据坐标到其中下载.具体关于中央仓库的介绍在后面. 2.    Maven坐标详解 比如下面一组坐标: <groupId>org.andy.items</groupId> &l

Maven学习笔记之——坐标和依赖(中)

Maven学习笔记之--坐标和依赖(中) 1.    传递性依赖 1.1    何为传递性依赖 项目中经常有引入一个jar包还要引入其他与其相关的jar包.自己搜的话要注意很多.比如版本问题等.而Maven会解析解析各个直接依赖的POM.将哪些必要的间接依赖以传递依赖的形式引入到项目中. 依赖范围不仅可以控制依赖与三种classpath关系.还对传递依赖产生影响. 假设A依赖B,B依赖C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖.第一直接依赖的范围和第二直接依赖

Maven学习笔记之——坐标和依赖(下)

Maven学习笔记之--坐标和依赖(下) 1.    最佳实践 归纳Maven依赖使用的常用技巧.方便用来避免和处理很多常见问题. 1.1.     排除依赖 传递性依赖会给项目隐式地引入很多依赖,这极大地简化了项目依赖的管理.但是有些时候这种特性也会带来问题.例如,当前项目有一个第三方依赖,而这个第三方依赖由于某些原因依赖了另外一个类库的SNAPSHOT版本,那么这个SNAPSHOT就会成为当前项目的传递性依赖,而SNAPSHOT的不稳定性会直接影响到当前的项目.这时候需要排除掉该SNAPSH

Maven学习笔记之坐标

作为依赖管理工具,Maven定义了坐标用于唯一标识构件在仓库中的位置,构成了依赖管理的底层基础. Maven构件的坐标包括: groupId定义隶属实际项目的名称,一般是隶属组织或公司域名的倒序加上实际项目名称: artifactId定义模块的名称,一般是实际项目名称加上子模块名称.一个模块可能包含多个子模块,便于模块化管理: version定义模块的版本,主要包括稳定版本和SNAPSHOT版本: packaging定义模块的打包方式,常用的打包方式包括: - jar是普通模块的打包方式,即不在

Maven学习笔记(四):协调和依赖

Maven协调具体的解释: Maven定义了这样一组规则:世界上不论什么一个构件都能够使用Maven坐标唯一标识.Maven坐标的元素包含groupId.artifactId.version.packaging.classifier.我们仅仅须要提供正确的坐标元素,Maven就能找到相应的构件.比方当须要使用Java5平台上的TestNG的5.8版本号时,就告诉Maven:"groupId=org.testng; artifactId=testng; version=5.8; classifer

maven学习笔记四(聚合和继承)

聚合 现在假如,我创建了3个maven项目, user-core.2.user-log,3.user-service 这个时候,假如我们要打包这些项目,要一个一个来,会很麻烦.那么我们有没有更好的办法通过只打包一个,来让其他都打包呢?ma 这个时候,我们就可以利用maven的聚合特性来实现.新建一个空的maven项目.如下图: 创建完毕后,打开pom.xml编写如下的配置: 这个时候,我们只需要执行这一个空的maven项目即完成了所有的项目的打包. 继承 现在假如,我创建了3个maven项目,

Maven学习笔记之——仓库(上)

Maven学习笔记之--仓库(上) 1.    何为maven仓库 Maven可以在某一指定位置统一存放所有maven项目共享的构件.此指定位置就是maven仓库.实际的项目将不再自己存放其所依赖的构件.他们只需要声明这些依赖的坐标.在需要的时候就会自动根据坐标找到仓库中的构件.并使用他们. 仓库的意义:减少磁盘占用空间.去除大量重复的构件.尤其是项目越来越多.越来越大的时候.更便于统一管理所有控件. 2.    仓库的布局 任何一个构件都有其唯一的坐标.根据这个坐标可以定义其在仓库中的唯一存储

Maven学习笔记(二):Maven仓库

Maven仓库的知识点比较少,理解起来也很简单. 仓库只有两类:本地仓库和远程仓库.所谓本地仓库就是自己机器上的仓库,在setting.xml文件中进行配置: 1 <localRepository>E:/MavenStore</localRepository> 本地仓库中存储的就是在使用Maven解析项目时从远程仓库下载的依赖和自己安装的一些构建. 远程仓库很明显就是网络上的仓库,存储在一个神秘的地方(好吧,其实我是不知道在哪里).当Maven解析项目时,如果本地没有需要的依赖,就

maven详解之坐标与依赖

看着简单而又复杂的pom.xml文件,看似熟悉,当自己编写的时候觉得简单,但是看人家项目的时候又觉得复杂的很,现在我们一起来分析这个pom文件. Maven的坐标为各种构件引入了秩序,任何一个构件都必须明确的定义自己的坐标,maven的坐标包括如下的元素: groupId: 定义当前Maven项目隶属的实际项目 artifactId: 该元素定义实际项目中的一个Maven项目或模块 version: 该元素定义Maven项目当前所处的版本 packaging: 该元素定义Maven项目的打包方式