1.4.4.传递性依赖

一个传递性依赖就是一个依赖的依赖。如果project-a依赖于project-b,而后者接着依赖于project-c,那么project-c就是被认为是project-a的传递性依赖。如果project-c依赖于project-d,那么project-d也被认为是project-a的传递性依赖。Maven的优势之一就是它能够管理传递性依赖,并且能够帮助开发者屏蔽掉跟踪所有编译期和运行期依赖细节。有了传递性依赖机制。在使用Spring Framework 的时候就不用去考虑它依赖了那些包,也不用担心一如多余的依赖。Maven会解析各个直接依赖的POM,将那些必须的间接依赖,以传递性依赖的形式引入到当前的项目中。

Maven建立一个依赖图,并且处理一些可能发生的冲突和重叠。

§传递性依赖的范围

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

compile

test

provided

runtime

Compile

compile

——

——

Runtime

Test

test

——

——

test

Provided

provided

——

provided

Provided

Runtime

runtime

——

——

runtime

如果project-a包含一个project-b的测试范围依赖,后者包含一个对于project-c的编译范围依赖。project-c将会是project-a的测试范围传统依赖。

从表中发现这样的规律:当第二个直接依赖范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;当第二个直接依赖范围是test的时候,传递性依赖不会得以传递;当第二个直接依赖范围是provided的时候,只传递第一直接依赖范围为provided的依赖。且传递性依赖的范围同样为provided;当第二直接依赖范围是runtime的时候,依赖性传递的范围与第一直接依赖的范围一致,但compile列外,此时传递性依赖的范围为runtime。

1.4.5.依赖版本界限

不是必须为依赖声明摸个特定的版本,可以指定一个满足需求的依赖版本界限。例如:项目依赖JUnit3.8或以上的版本,或者说依赖于JUnit1.2.10和1.2.14之间的某个版本。可以使用如下的字符来围绕一个或者多个版本号,开实现版本界限(,)不包含量词,[, ]包含量词。例如想访问JUnit任意大于等于3.8但小于4.0版本的

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>[3.8,4.0)</version>

<scope>test</scope>

</dependency>

如果想要依赖任意不大于3.8.1的版本,可以只指定一个上包含边界。

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>[,3.8.1]</version>ex-de

<scope>test</scope>

</dependency>

在逗号前面或者后面的版本不是必须的,这种空缺意味着正无穷或者负无穷。

注意:当生命一个“正常的”版本如JUnit3.8.2,最好表述成“允许任何版本,最好是3.8.2”。当检测到版本冲突的时候,Maven会使用冲突算法来选择最好的版本。如果指定[3.8.2],它意味只有3.8.2会被使用,没有其它地方依赖地使用了一个版本[3.8.1],就会得到一个构建失败的报告,说明有版本冲突。要保守党的使用它,只有在确实需要的时候才使用。正好的做法是通过dependencyManagement来解决冲突。

1.4.6.依赖调解

Maven引入的传递性依赖机制,一方面大大简化和方便了依赖声明,另一方面,大部分情况下只需要关心项目的直接依赖,而不用考虑这些直接依赖会引入那些传递性依赖。但是有时候,当传递性依赖造成问题的时候,需要清楚地知道该传递性依赖是从哪条依赖路径引入的。例如:项目A有这样的依赖关系:A -> B -> C -> X(1.0), A-> D -> X(2.0),X是A的传递性依赖,但是两条依赖路径上有两个版本的X,那么哪个X会被Maven解析使用呢?两个版本都被解析显然是不对的,因为会造成依赖重复,因此必须选择一个。Maven依赖调解的第一个原则是:路径最近者优先。该例中X(1.0)的路径长度为3,而X(2.0)路径长度为2,因此X(2.0)会被解析使用。

依赖调解第一原则不能解决所有问题,例如依赖关系A –> B -> Y(1.0),A -> B ->Y(2.0),Y(1.0)和Y(2.0)的依赖路径长度都是2。在Maven2.0.8及之前的版本中,这是不确定的,但是从Maven2.0.9开始,为了尽可能避免构建的不确定,Maven定义了依赖调解的第二原则:第一原则优先,在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会解析使用,顺序最靠前的那个依赖被使用。如果B的依赖声明在C之前,那么Y(1.0)就会被解析使用。

1.4.7.可选依赖

假设有这样一个依赖关系,项目A依赖于项目B,项目B依赖于项目X和Y,B对于X和Y的依赖都是可选依赖:A -> B, B ->X(可选),B -> y(可选)。根据传递性依赖的定义,如果所有这三个依赖的范围都是compile,那么X,Y就是A的compile范围传递性依赖。然而,由于这里X,Y是可选依赖,依赖将不会的依传递。X,Y将不会对A有任何影响。项目B实现了两个特征,其中特征一依赖于X,特征二依赖于Y,而且这两个特征是互斥的,用户不可能同时使用两个。在编译B项目时需要两个依赖,如下:

<project>

<modelVersion>4.0.0</modelVersion>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>my-project-b</artifactId>

<version>1.0.0</version>

<dependencies>

<dependency>

<groupId>net.sf.ehcache</groupId>

<artifactId>ehcache</artifactId>

<version>1.4.1</version>

<optional>true</optional>

</dependency>

<dependency>

<groupId>swarmcache</groupId>

<artifactId>swarmcache</artifactId>

<version>1.0RC2</version>

<optional>true</optional>

</dependency>

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.13</version>

</dependency>

</dependencies>

</project>

上述XML代码片段中,使用<optional>元素表示net.sf.ehcache和swarmcache这两个依赖为可选依赖,它们只会对当前项目B产生影响,当其它项目依赖于B的时候,这两个依赖不会被传递。因此,当A依赖于项目B的时候,那么在项目A中就要显示的声明使用哪种依赖项。

<project>

<modelVersion>4.0.0</modelVersion>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>my-application</artifactId>

<version>1.0.0</version>

<dependencies>

<dependency>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>my-project</artifactId>

<version>1.0.0</version>

</dependency>

<dependency>

<groupId>net.sf.ehcache</groupId>

<artifactId>swarmcache</artifactId>

<version>1.4.1</version>

</dependency>

</dependencies>

</project>

注意:在理想的情况下,是不应该使用可选依赖的。使用可选依赖的原因是某一个项目实现了多个特征,在面向对象设计中,有一个单一责任原则,意指一个类应该只有一项职责,而不是糅合太多的功能,这个原则在规划Maven项目的时候也同样适用。

1.4.8.排除依赖

有很多时候需要排除一个传递性依赖,就要适用exclusions元素声明排除依赖。

<dependency>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>project-a</artifactId>

<version>1.0</version>

<exclusions>

<exclusion>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>project-b</artifactId>

</exclusion>

</exclusions>

</dependency>

exclusions可以包含一个或者多个exclusion子元素。

排除并且替换一个传递性依赖。

<dependencies>

<dependency>

<groupId>org.hibernate</groupId>

<artifactId>hibernate</artifactId>

<version>3.2.5.ga</version>

<exclusions>

<exclusion>

<groupId>javax.transaction</groupId>

<artifactId>jta</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.apache.geronimo.specs</groupId>

<artifactId>geronimo-jta_1.1_spec</artifactId>

<version>1.1</version>

</dependency>

</dependencies>

没有标记说依赖geronimo-jta_1.1_spec是一个替换,它只是正好提供了原来JTA依赖一样的API。有以下几种情况可能想要排除或者替换传递性依赖的情况:

§构建的groupId和artifactId已经改变,而当前项目需要一个传递性依赖不同名称的版本—结果是classpath中会出现同样项目的两份内容。一般来说Maven会捕获到这种冲突并且使用该项目的一个单独的版本,但是当artifactId和gruopId不一样的时候,Maven就会认为他们是两种不同的类库。

§某个构件没有在项目中被使用,而且该传递性依赖没有被标示为可选依赖的这种情况下,可能要排除这样依赖,因为它不是系统需要的东西,尽量减少应用程序发布时的类库数目。

§一个构件已经在运行时的容器中提供了,因此不应该被包含在构件中。

§为了排除一个可能是多个实现的API依赖。

1.4.9.归类依赖

有很多关于Spring Framework的依赖,它们分别是spring-aop,spring-beans,spring-context,spring-context-support,spring-core等,它们是来自同一项目的不同模块,因此,是由于这些依赖的版本都是相同的。如果将要升级Spring Framework,这些依赖的版本会一起升级。所以应该在一个唯一的地方定义一个版本,并且在dependency声明中引用这一版本,这样在升级Spring Framework的时候就只需要修改一处。

<project>

<modelVersion>4.0.0</modelVersion>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>my-project</artifactId>

<version>1.0.0-SNAPSHOT</version>

<properties>

<springframework.version>3.0.0.RELEASE</springframework.version>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-aop</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>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-core</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jdbc</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-orm</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-tx</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jms</artifactId>

<version>${springframework.version}</version>

</dependency>

</dependencies>

</project>

1.4.10.依赖管理

Maven提供dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证自模块依赖的使用灵活性。

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

正确的做法是:

1. 在父模块中使用dependencyManagement配置依赖

2. 在子模块中使用dependencies添加依赖

dependencyManagement实际上不会真正引入任何依赖,dependencies才会。但是,当父模块中配置了某个依赖之后,子模块只需使用简单groupId和artifactId就能自动继承相应的父模块依赖配置。

父模块中如此声明:

<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)的依赖配置只有一种,这样就能避免引入不同版本的依赖,避免依赖冲突。

1.4.11.优化依赖

§mvn dependency:list 此命令查看当前项目的已解析的依赖。

§mvndependency:tree 此命令查看当前项目的依赖树。

§mvndependency:analyze 此命令可以帮助分析当前项目的依赖。使用但未声明的依赖与声明但未使用的依赖。

使用以上命令可以帮助我们了解项目所有依赖的具体情况。

转载于:https://blog.51cto.com/lizhengyang/1224554

maven项目对象模型(二)相关推荐

  1. MAVEN项目对象模型,原来找Bug也不用如此费时费事。

    解释之前,提个小问题 假如你正在Eclipse下开发两个Java项目,姑且把它们称为A.B,其中A项目中的一些功能依赖于B项目中的某些类,那么如何维系这种依赖关系的呢? 很简单,这不就是跟我们之前写程 ...

  2. 搭建SpringMVC+Hibernate4+Spring3+Ajax+Maven项目(二)

    相信大家看了上篇文章应该都搭建起SpringMVC+Hibernate4+Spring3+Ajax+Maven项目了,应该都正常跑起来了,下面继续上篇文章的填坑之路. 首先从maven的jar包配置文 ...

  3. Maven学习总结(十一)——Maven项目对象模型pom.xml文件详解

    2019独角兽企业重金招聘Python工程师标准>>> <project xmlns="http://maven.apache.org/POM/4.0.0" ...

  4. Maven项目构建工具

    目录 1.Maven介绍 1.1Maven是什么 1.2为什么要使用maven 2.Maven安装 2.1下载Maven: 2.2解压并配置 2.3编辑Maven环境变量 2.3.1检查JDK环境变量 ...

  5. idea创建maven项目 [超详细]

    一.背景. IDEA是用于java语言开发的集成环境,并且经常用于maven.spring.MyBatis等项目的开发.今天将为大家介绍如何在IDEA中创建Maven项目. 二.idea创建maven ...

  6. Maven项目简单介绍

    什么是maven项目 Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件. Apache Maven是一个软件项目管理和依赖管理工具.基于项目对象模 ...

  7. Maven学习总结(二)——Maven项目构建过程练习

    2019独角兽企业重金招聘Python工程师标准>>> Maven学习总结(二)--Maven项目构建过程练习 上一篇只是简单介绍了一下maven入门的一些相关知识,这一篇主要是体验 ...

  8. IntelliJ IDEA 14 创建maven项目二

    前言: 在我的idea14使用maven创建web工程文章介绍了如何运用idea14创建maven项目--但有瑕疵,如下: 今天在群里交流才得知起因: 原来一直这样创建的--但结果都一样,均出现上面的 ...

  9. 二、IDEA创建Maven项目

    一.IDEA配置maven 当导入maven项目的时候,首先需要按照如图进行maven的配置:指定使用的maven包.指定本地仓库和maven的settings.xml文件. 然后在IDEA右侧栏,点 ...

  10. java maven 项目依赖管理 简介

    目录 一.简单的小问题? 二.maven到底是什么? 三.maven的安装 四.仓库的概念 五.使用命令行管理maven项目 六.使用Myeclipse创建maven自定义项目 七.pom.xml的依 ...

最新文章

  1. SUSE LINUX下文件系统变只读的问题解决
  2. Node.js 究竟是什么?(zz)
  3. FastDFS工具类的使用
  4. 进入postgresql
  5. hive中文字符乱码 解决方法【转】
  6. 揭秘python的5种最佳调试方法_揭秘 IPython 的 5 种最佳调试方法-阿里云开发者社区...
  7. Java方法中的参数太多,第5部分:方法命名
  8. 矩阵论-线性变换的特征值与特征变换
  9. 关系数据模型和关系数据库系统
  10. 项目经理应如何调动员工的积极性
  11. jQuery的表单验证
  12. 性能测试工具Loadrunner使用之一(Virtual User Generato)
  13. Java、对字符串中的字符排序
  14. PCB检查流程checklist
  15. 西瓜数据集3.0 python_决策树对西瓜数据集2.0二分类
  16. 教你如何鉴别iPhone翻新机!
  17. 中通快递api,中通快递一件代发api,中通快递礼品商城api,中通快递空包api
  18. 戴尔笔记本电脑XPS15-9560混盘更换成SM961与SATA3固盘的步骤和方法
  19. 皮带撕裂检测matlab,基于机器视觉的皮带纵向撕裂检测方法
  20. php移动端可拖动可视化,可视化编辑uniapp项目DIY拖拽

热门文章

  1. 可视化排班管理_呼叫中心外包之管理要点与数据分析对策
  2. python异步教程_Python开发异步任务Celery的使用教程!
  3. java分布式_学习分布式无从入手?阿里Java架构师分享分布式架构必读书籍
  4. POJ3253-Fence Repair
  5. linux RAID10测试
  6. MySQL 数据库重装失败最后一步无法启动server的解决办法
  7. Linux运维之道(大量经典案例、问题分析,运维案头书,红帽推荐)
  8. 获取linux系统信息的一个python脚本
  9. C语言实现日期转换小工具
  10. 【算法】排序_归并排序