9. 依赖关系

转载地址

项目的依赖关系主要分为三种:依赖,继承,聚合

依赖关系

依赖关系是最常用的一种,就是你的项目需要依赖其他项目,比如Apache-common包,Spring包等等。


<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.11</version>
   <scope>test</scope>
   <type >jar</ type >
   <optional >true</ optional >
 </dependency>

任意一个外部依赖说明包含如下几个要素:groupId, artifactId, version, scope, type, optional。其中前3个是必须的。
这里的version可以用区间表达式来表示,比如(2.0,)表示>2.0[2.0,3.0)表示2.0<=ver<3.0;多个条件之间用逗号分隔,比如[1,3],[5,7]
type 一般在pom引用依赖时候出现,其他时候不用。

maven认为,程序对外部的依赖会随着程序的所处阶段和应用场景而变化,所以maven中的依赖关系有作用域(scope)的限制。在maven中,scope包含如下的取值:

  • compile(编译范围)
    compile是默认的范围;如果没有提供一个范围,那该依赖的范围就是编译范围。编译范围依赖在所有的classpath中可用,同时它们也会被打包。
  • provided(已提供范围)
    provided依赖只有在当JDK或者一个容器已提供该依赖之后才使用。例如,如果你开发了一个web应用,你可能在编译classpath中需要可用 的Servlet API来编译一个servlet,但是你不会想要在打包好的WAR中包含这个Servlet API;这个Servlet API JAR由你的应用服务器或者servlet容器提供。已提供范围的依赖在编译classpath(不是运行时)可用。它们不是传递性的,也不会被打包。
  • runtime(运行时范围)
    runtime依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要JDBC API JAR,而只有在运行的时候才需要JDBC驱动实现。
  • test(测试范围)
    test范围依赖在编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用。
  • system(系统范围)
    system范围依赖与provided类似,但是你必须显式的提供一个对于本地系统中JAR文件的路径。这么做是为了允许基于本地对象编译,而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven也不会在仓库中去寻找它。 如果你将一个依赖范围设置成系统范围,你必须同时提供一个systemPath元素 。注意该范围是不推荐使用的(应该一直尽量去从公共或定制的Maven仓库中引用依赖)。

dependency中的type一般不用配置,默认是jar。当type为pom时,代表引用关系:

<dependency>
     <groupId>org.sonatype.mavenbook</groupId>
     <artifactId>persistence-deps</artifactId>
     <version>1.0</version>
     <type>pom</type>
</dependency>

此时,本项目会将persistence-deps的所有jar包导入依赖库。
可以创建一个打包方式为pom项目来将某些通用的依赖归在一起,供其他项目直接引用,不要忘了指定依赖类型为pom(<type>pom</type>)。

继承关系

继承就是避免重复,maven的继承也是这样,它还有一个好处就是让项目更加安全。项目之间存在上下级关系时就属于继承关系。
父项目的配置如下:


<project>  
      <modelVersion>4.0.0</modelVersion>  
      <groupId>org.clf.parent</groupId>  
      <artifactId>my-parent</artifactId>  
      <version>2.0</version>  
      <packaging>pom</packaging> 
      
      <!-- 该节点下的依赖会被子项目自动全部继承 -->
      <dependencies>
        <dependency>
               <groupId>org.slf4j</groupId>
               <artifactId>slf4j-api</artifactId>
               <version>1.7.7</version>
               <type>jar</type>
               <scope>compile</scope>
        </dependency>
      </dependencies>
      
      <dependencyManagement>
        <!-- 该节点下的依赖关系只是为了统一版本号,不会被子项目自动继承,-->
        <!--除非子项目主动引用,好处是子项目可以不用写版本号 -->
        <dependencies>
           <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-orm</artifactId>
                <version>4.2.5.RELEASE</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>4.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>4.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>4.2.5.RELEASE</version>
            </dependency>
        </dependencies>
       </dependencyManagement>

       <!-- 这个元素和dependencyManagement相类似,它是用来进行插件管理的-->
       <pluginManagement>  
       ......
       </pluginManagement>
</project>

注意,此时<packaging>必须为pom
为了项目的正确运行,必须让所有的子项目使用依赖项的统一版本,必须确保应用的各个项目的依赖项和版本一致,才能保证测试的和发布是相同的结果。
Maven 使用dependencyManagement 元素来提供了一种管理依赖版本号的方式。通常会在一个组织或者项目的最顶层的父POM 中看到dependencyManagement 元素。使用pom.xml 中的dependencyManagement 元素能让所有在子项目中引用一个依赖而不用显式的列出版本号。Maven 会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用在这个dependencyManagement 元素中指定的版本号。
父项目在dependencies声明的依赖,子项目会从全部自动地继承。而父项目在dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。
如果某个项目需要继承该父项目,基础配置应该这样:

<project>  
      <modelVersion>4.0.0</modelVersion>  
      <groupId>org.clf.parent.son</groupId>  
      <artifactId>my-son</artifactId>  
      <version>1.0</version> 
      <!-- 声明将父项目的坐标 -->
      <parent>
          <groupId>org.clf.parent</groupId>  
          <artifactId>my-parent</artifactId>  
          <version>2.0</version>  
          <!-- 父项目的pom.xml文件的相对路径。相对路径允许你选择一个不同的路径。 -->
          <!--  默认值是../pom.xml。Maven首先在构建当前项目的地方寻找父项目的pom, -->
          <!--  其次在文件系统的这个位置(relativePath位置), -->
          <!--  然后在本地仓库,最后在远程仓库寻找父项目的pom。 -->
          <relativePath>../parent-project/pom.xml</relativePath>
      </parent> 
      
      <!-- 声明父项目dependencyManagement的依赖,不用写版本号 -->
      <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-web</artifactId>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-beans</artifactId>
          </dependency>
      </dependencies>
       
</project>

聚合关系

随着技术的飞速发展和各类用户对软件的要求越来越高,软件本身也变得越来越复杂,然后软件设计人员开始采用各种方式进行开发,于是就有了我们的分层架构、分模块开发,来提高代码的清晰和重用。针对于这一特性,maven也给予了相应的配置。
maven的多模块管理也是非常强大的。一般来说,maven要求同一个工程的所有模块都放置到同一个目录下,每一个子目录代表一个模块,比如:

总项目/
     pom.xml 总项目的pom配置文件
     子模块1/
           pom.xml 子模块1的pom文件
     子模块2/
          pom.xml子模块2的pom文件

总项目的配置如下:

<project> 
       <modelVersion>4.0.0</modelVersion> 
       <groupId>org.clf.parent</groupId> 
       <artifactId>my-parent</artifactId> 
       <version>2.0</version> 
       
       <!-- 打包类型必须为pom -->
       <packaging>pom</packaging>
       
       <!-- 声明了该项目的直接子模块 -->
       <modules>
       <!-- 这里配置的不是artifactId,而是这个模块的目录名称-->
        <module>module-1</module>
        <module>module-2</module>
        <module>module-3</module>
    </modules>
       
       <!-- 聚合也属于父子关系,总项目中的dependencies与dependencyManagement、pluginManagement用法与继承关系类似 -->
       <dependencies>
        ......
       </dependencies>
        
       <dependencyManagement>
        ......
       </dependencyManagement>
 
       <pluginManagement> 
       ......
       </pluginManagement>
</project> 

子模块的配置如下:

<project> 
       <modelVersion>4.0.0</modelVersion> 
       <groupId>org.clf.parent.son</groupId> 
       <artifactId>my-son</artifactId> 
       <version>1.0</version>
       <!-- 声明将父项目的坐标 -->
       <parent>
              <groupId>org.clf.parent</groupId> 
              <artifactId>my-parent</artifactId> 
              <version>2.0</version> 
       </parent>
</project>

继承与聚合的关系

首先,继承与聚合都属于父子关系,并且,聚合 POM与继承关系中的父POM的packaging都是pom。
不同的是,对于聚合模块来说,它知道有哪些被聚合的模块,但那些被聚合的模块不知道这个聚合模块的存在。对于继承关系的父 POM来说,它不知道有哪些子模块继承与它,但那些子模块都必须知道自己的父 POM是什么。
在实际项目中,一个 POM往往既是聚合POM,又是父 POM,它继承了某个项目,本身包含几个子模块,同时肯定会存在普通的依赖关系,就是说,依赖、继承、聚合这三种关系是并存的。

Maven可继承的POM 元素列表如下:

  • groupId :项目组 ID ,项目坐标的核心元素;
  • version :项目版本,项目坐标的核心元素;
  • description :项目的描述信息;
  • organization :项目的组织信息;
  • inceptionYear :项目的创始年份;
  • url :项目的 url 地址
  • develoers :项目的开发者信息;
  • contributors :项目的贡献者信息;
  • distributionManagerment:项目的部署信息;
  • issueManagement :缺陷跟踪系统信息;
  • ciManagement :项目的持续继承信息;
  • scm :项目的版本控制信息;
  • mailingListserv :项目的邮件列表信息;
  • properties :自定义的 Maven 属性;
  • dependencies :项目的依赖配置;
  • dependencyManagement:醒目的依赖管理配置;
  • repositories :项目的仓库配置;
  • build :包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等;
  • reporting :包括项目的报告输出目录配置、报告插件配置等。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,748评论 6 342
  • 好久没有更新了,在这里给大家说声抱歉,实在是因为最近加班忙成狗,还有一个原因是我想把《maven实战》这本书剩下的...
    小炼君阅读 1,436评论 0 51
  • 当前,JVM生态圈主要的三大构建工具: Apache Ant(带着Ivy) Maven Gradle 对于刚开始接...
    清枫_小天阅读 5,774评论 1 13
  • 前言什么是 POMQuick Overview POM 常用元素 pom.xml 完整注释 参考 0 前言 什么是...
    seyvoue阅读 12,575评论 1 36