03-maven的坐标和依赖

Maven-坐标、依赖


pom.xml主体

<?xml version="1.0" encoding="UTF-8"?>
<!--  maven的根节点及schema -->
 <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">  
 
<!-- 坐标代码 -->
<!-- 依赖代码 -->
 
<project>
以下的代码都在project标签中,本文只对各个标签进行描述,初学者可能看不懂,可快速浏览,为之后的学习做准备

坐标

<!--声明项目描述符遵循哪一个POM模型版本。模型本身的版本很少改变,虽然如此,
        但它仍然是必不可少的,这是为了当Maven引入了新的特性或者其他模型变更的时候,确保稳定性。-->   
<modelVersion>4.0.0</modelVersion>  
 
<!--项目的全球唯一标识符,通常使用全限定的包名区分该项目和其他项目。
    并且构建时生成的路径也是由此生成, 如com.mycompany.app生成的相对路径为:/com/mycompany/app--> 
<!-- groupId:组id,公司网址的反写+项目名称。
    如下:com.yyoo是公司名称,maven01是项目名称 -->
<groupId>asia.banseon</groupId>  
 
<!--构件的标识符,它和group ID一起唯一标识一个构件。换句话说,
    你不能有两个不同的项目拥有同样的artifact ID和groupID;在某个特定的group ID下,
    artifact ID也必须是唯一的。构件是项目产生的或使用的一个东西,Maven为项目产生的构件包括:
    JARs,源码,二进制发布和WARs等。--> 
<!-- artifactId:项目id,实际对应项目的名称-模块名称
      此名称和mvn package、mvn install 生成后的文件有关系-->
<artifactId>banseon-maven2</artifactId>  
 
<!--项目当前版本,格式为:主版本.次版本.增量版本-限定版本号
    SNAPSHOT:快照版本
    alpha:内部测试版本
    beta:公测版本
    release:稳定版本
    GA:正式发布版本
--> 
<version>0.0.1-SNAPSHOT</version>  
 
<!--项目产生的构件类型,默认jar,例如jar、war、ear、pom。
    插件可以创建他们自己的构件类型,所以前面列的不是全部构件类型--> 
<packaging>jar</packaging>  
 
<!--项目的名称, Maven产生的文档用--> 
<name>banseon-maven</name>  
 
<!--项目主页的URL, Maven产生的文档用--> 
<url>http://www.baidu.com/banseon</url>  
 
<!--项目的详细描述, Maven 产生的文档用。  当这个元素能够用HTML格式描述时
    (例如,CDATA中的文本会被解析器忽略,就可以包含HTML标签), 不鼓励使用纯文本描述。
    如果你需要修改产生的web站点的索引页面,你应该修改你自己的索引页文件,而不是调整这里的文档。
--> 
<description>A maven project to study maven.</description>

依赖

<!--
该元素描述了项目相关的所有依赖。 这些依赖组成了项目构建过程中的一个个环节。
它们自动从项目定义的仓库中下载。要获取更多信息,请看项目依赖机制。
 -->
<dependencies>
    <dependency>
        <!--依赖的group ID -->
        <groupId>org.apache.maven</groupId>
         
        <!--依赖的artifact ID -->
        <artifactId>maven-artifact</artifactId>
         
        <!--依赖的版本号。 在Maven 2里, 也可以配置成版本号的范围。 -->
        <version>3.8.1</version>
         
        <!--依赖类型,默认类型是jar。它通常表示依赖的文件的扩展名,但也有例外。
        一个类型可以被映射成另外一个扩展名或分类器。类型经常和使用的打包方式对应,
        尽管这也有例外。一些类型的例子:jar,war,ejb-client和test-jar。如果设置extensions为 
            true,就可以在plugin里定义新的类型。所以前面的类型的例子不完整。 -->
        <type>jar</type>
         
        <!--依赖的分类器。分类器可以区分属于同一个POM,但不同构建方式的构件。
        分类器名被附加到文件名的版本号后面。例如,如果你想要构建两个单独的构件成JAR,一个使用Java 
            1.4编译器,另一个使用Java 6编译器,你就可以使用分类器来生成两个单独的JAR构件。 -->
        <classifier></classifier>
         
        <!--依赖范围。在项目发布过程中,帮助决定哪些构件被包括进来。欲知详情请参考依赖机制。 
            - compile :默认范围,在编译、测试、运行都有效 
            - provided:类似于编译,但支持你期待jdk或者容器提供,类似于classpath。在编译和测试有效。 
            - runtime: 在执行时需要使用。 在测试和运行时有效。
            - test: 用于test任务时使用。测试时有效。 
            - system: 需要外在提供相应的元素。通过systemPath来取得。与本机系统相关联,可移植性差。 
            - systemPath: 仅用于范围为system。提供相应的路径 
            - import : 导入的范围,只使用在dependencyManagement标签中,表示从其他的pom中导入dependency。
                -->
        <scope>test</scope>
         
        <!--仅供system范围使用。注意,不鼓励使用这个元素,并且在新的版本中该元素可能被覆盖掉。
        该元素为依赖规定了文件系统上的路径。需要绝对路径而不是相对路径。推荐使用属性匹配绝对路径,
        例如${java.home}。 -->
        <systemPath></systemPath>
         
        <!--当计算传递依赖时, 从依赖构件列表里,列出被排除的依赖构件集。即告诉maven你只依赖指定的项目,
        不依赖项目的依赖。此元素主要用于解决版本冲突问题 -->
        <exclusions>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
            </exclusion>
        </exclusions>
         
        <!--是否是可选依赖,默认false,如果你在项目B中把C依赖声明为可选,你就需要在依赖于B的项目(例如项目A)
        中显式的引用对C的依赖。可选依赖阻断依赖的传递性。 -->
        <optional>true</optional>
    </dependency>
</dependencies>

依赖管理

<!--
 继承自该项目的所有子项目的默认依赖信息。这部分的依赖信息不会被立即解析,
 而是当子项目声明一个依赖(必须描述group ID和artifact ID信息),
 如果group ID和artifact ID以外的一些信息没有描述,
 则通过group ID和artifact ID匹配到这里的依赖,并使用这里的依赖信息。 
 -->
<dependencyManagement>
    <dependencies>
        <!--参见dependencies/dependency元素 -->
        <dependency>
            ......
        </dependency>
    </dependencies>
</dependencyManagement>

parent父项目

<!--父项目的坐标。如果项目中没有规定某个元素的值,那么父项目中的对应值即为项目的默认值。 坐标包括group ID,artifact ID和 version。-->
<parent>
    <!--被继承的父项目的构件标识符 -->
    <artifactId></artifactId>
    <!--被继承的父项目的全球唯一标识符 -->
    <groupId></groupId>
    <!--被继承的父项目的版本 -->
    <version></version>
    <!--父项目的pom.xml文件的相对路径。相对路径允许你选择一个不同的路径。默认值是../pom.xml。Maven首先在构建当前项目的地方寻找父项目的pom,
               其次在文件系统的这个位置(relativePath位置),然后在本地仓库,最后在远程仓库寻找父项目的pom。注意:父项目的packaging的值必须为pom
               如果父项目已经发布到仓库(当前项目能够访问的仓库,如果私服仓库),该选项可以不写
    -->
    <relativePath></relativePath>
</parent>

最简单的依赖

<dependency>  
  <groupId>junit</groupId>  
  <artifactId>junit</artifactId>  
  <version>4.4</version>  
</dependency> 
依赖是使用Maven坐标来定位的,而Maven坐标主要由GAV(groupId, artifactId, version)构成。因此,使用任何一个依赖之间,你都需要知道它的Maven坐标。关于如何确定坐标。将在后面讲解。上例中我们声明了一个对junit的依赖,它的groupId是junit, artifactId是junit, version是4.4。这一组GAV构成了一个Maven坐标,基于此,Maven就能在本地或者远程仓库中找到对应的junit-4.4.jar文件。

依赖范围(scope)

对于Junit,一般来说你只有在运行测试的时候需要它,也就是说,它对于src/main/java的classpath没什么意义,并且,将Junit的jar文件打入最终的发布包也不是好事,这无谓的增加了发布包的大小。其实我们应该这样做:

<dependency>  
  <groupId>junit</groupId>  
  <artifactId>junit</artifactId>  
  <version>4.4</version>  
  <scope>test</scope>  
</dependency> 
于是,junit对于主源码classpath不可用,对于测试源码classpath可用,不会被打包。再举个例子,在开发javaee应用的时候我们一定会用到servlet-api,它对于主源码和测试源码都是必要的,因为我们的代码中会引入servlet-api的包。但是,在打包的时候,将其放入WAR包就会有问题,因为web容器会提供servlet-api,如果我们再将其打包就会造成依赖冲突,解决方案如下:

<dependency>  
  <groupId>javax.servlet</groupId>  
  <artifactId>servlet-api</artifactId>  
  <version>2.4</version>  
  <scope>provided</scope>  
</dependency> 
将依赖范围设置成provided,就意味着该依赖对于主源码classpath,以及测试classpath可用,但不会被打包。这正是servlet-api所需要的。

主要的依赖范围以及作用:

compile:编译依赖范围(默认),使用此依赖范围对于编译、测试、运行三种 classpath 都有效,即在编译、测试和运行的时候都要使用该依赖jar包;

test:测试依赖范围,从字面意思就可以知道此依赖范围只能用于测试classpath,而在编译和运行项目时无法使用此类依赖,典型的是JUnit,它只用于编译测试代码和运行测试代码的时候才需要;

provided:此依赖范围,对于编译和测试classpath有效,而对运行时无效;

runtime:运行时依赖范围,对于测试和运行classpath有效,但是在编译主代码时无效,典型的就是JDBC驱动实现;

system:系统依赖范围,使用system范围的依赖时必须通过systemPath元素显示地指定依赖文件的路径,不依赖Maven仓库解析,所以可能会造成建构的不可移植,谨慎使用

import:导入依赖范围。

依赖范围(scope)主源码classpath可用(compile)测试源码classpath可用(test)运行源码classpath可用(runtime)会被打包
compile 缺省值TRUETRUETRUETRUE
testFALSETRUEFALSEFALSE
runtimeFALSETRUETRUETRUE
providedTRUETRUEFALSEFALSE

分类器(classifer)

GAV是Maven坐标最基本最重要的组成部分,但GAV不是全部。还有一个元素叫做分类器(classifier),90%的情况你不会用到它,但有些时候,分类器非常不可或缺。举个简单的例子,当我们需要依赖TestNG的时候,简单的声明GAV会出错,因为TestNG强制需要你提供分类器,以区别jdk14和jdk15,我们需要这样声明对TestNG的依赖:

<dependency>  
  <groupId>org.testng</groupId>  
  <artifactId>testng</artifactId>  
  <version>5.7</version>  
  <classifier>jdk15</classifier>  
</dependency>   

你会注意到maven下载了一个名为testng-5.7-jdk15.jar的文件。其命名模式实际上是artifactId-version-classifier.packaging。理解了这个模式以后,你就会发现很多文件其实都是默认构件的分类器扩展,如 myapp-1.0-test.jar, myapp-1.0-sources.jar。

分类器还有一个非常有用的用途是:我们可以用它来声明对test构件的依赖,比如,我们在一个核心模块的src/test/java中声明了一些基础类,然后我们发现这些测试基础类对于很多其它模块的测试类都有用。没有分类器,我们是没有办法去依赖src/test/java中的内容的,因为这些内容不会被打包到主构件中,它们单独的被打包成一个模式为artifactId-version-test.jar的文件。我们可以使用分类器来依赖这样的test构件:

<dependency>  
  <groupId>org.myorg.myapp</groupId>  
  <artifactId>core</artifactId>  
  <version>${project.version}</version>  
  <classifier>test</classifier>  
</dependency> 

依赖管理(dependencyManagement)

实际的项目中,你会有一大把的Maven模块,而且你往往发现这些模块有很多依赖是完全项目的,A模块有个对spring的依赖,B模块也有,它们的依赖配置一模一样,同样的groupId, artifactId, version,或者还有exclusions, classifer。细心的分会发现这是一种重复,重复就意味着潜在的问题,Maven提供的dependencyManagement就是用来消除这种重复的。正确的做法是:

  1. 在父模块中使用dependencyManagement配置依赖
  2. 在子模块中使用dependencies添加依赖

dependencyManagement实际上不会真正引入任何依赖,dependencies才会。但是,当父模块中配置了某个依赖之后,子模块只需使用简单groupId和artifactId(这样在依赖的地方就可以不使用version等)就能自动继承相应的父模块依赖配置。例如:

父模块中如此声明:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.sonatype.mavenbook</groupId>
    <artifactId>a-parent</artifactId>
    <version>1.0.0</version>
    ...
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.2</version>
            </dependency>
            ...
            <dependencies>
    </dependencyManagement>  
 </project>
子模块中如此声明:
<project>  
  <modelVersion>4.0.0</modelVersion>  
  <parent>  
    <groupId>org.sonatype.mavenbook</groupId>  
    <artifactId>a-parent</artifactId>  
    <version>1.0.0</version>  
  </parent>  
  <artifactId>project-a</artifactId>  
  ...  
  <dependencies>  
    <dependency>  
      <groupId>mysql</groupId>  
      <artifactId>mysql-connector-java</artifactId>  
    </dependency>  
  </dependencies>  
</project>
你依赖配置越复杂,依赖管理所起到的作用就越大,它不仅能够帮助你简化配置,它还能够帮你巩固依赖配置,也就是说,在整个项目中,对于某个构件(如mysql)的依赖配置只有一种,这样就能避免引入不同版本的依赖,避免依赖冲突。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值