依赖管理是maven的一个广为人知的特性, 这也是maven擅长的一个领域. 为单一的工程管理依赖不是很难, 但当你着手处理多模块工程和包含数十或数百个模块的应用时, maven可以帮助你很好地保持高度控制和稳定性.

Transitive Dependencies

依赖传递性是 maven 2.0中的一个新特性. 这不需要你去搜索和指定你自己的依赖需要的库, 而是自动地包含它们.

这个特性通过从指定的远程仓库读取你依赖的工程文件. 通常, 那些工程的所有依赖关系都会用于你的工程, 因为该项目从其父母或依赖关系中继承了这些.

没有限制依赖的组织层次数目, 但如果发现一个循环依赖就会发生问题.

由于依赖传递, 包含库的关系图会迅速变得很大. 因此, 有一些额外的特性来限制哪些依赖被包含:

(1) Dependency mediation. 依赖调解. 这决定了, 当一个构件的多个版本相遇时, 使用哪个版本的依赖. 目前, maven 2.0 只支持使用最近的定义("nearest definition"), 就是说, 它将使用在依赖树中离你的项目最近的版本. 你可以显式地在项目的pom文件中声明, 保证总是使用某个特定的版本. 注意, 如果2个依赖版本在依赖树中的深度一样, 在maven 2.0.8之前, 它没有定义哪个版本会胜出, 但从maven 2.0.9, 由声明的顺序来决定, 第一声明者优先.

nearest definition, 是指在依赖树中离你的工程最近的那个版本. 比如, 如果A,B,C之间的依赖关系为: A->B->C->D 2.0, 以及 A->E->D 1.0, 这样, 当构建A时, 将会使用 D 1.0. 因为从A到D的路径, 后者更短.  你可以显式地在A中添加一个依赖 D 2.0, 强制使用D 2.0.

(2) Dependency management. 依赖管理. 当构件在依赖传递中 或没有指定版本的依赖中相遇时, 工程作者可以直接 指定使用构件的哪个版本. 在上一节的例子中, 一个依赖会被添加到A中, 即使它不是直接被A使用. 相反, A可以在它的依赖管理中包含D作为一个依赖, 直接控制D在被引用时使用哪个版本.

(3) Dependency scope. 依赖范围. 只包含适合当前构建阶段的依赖. 下面会详细描述这一点.

(4) Excluded dependencies. 排除依赖. 如果工程X依赖工程Y, 工程Y依赖工程Z, 工程X的所有者可以显式地排除工程Z作为一个依赖, 使用 exclusion 元素 .

(5) Optional dependencies. 可选依赖. 如果工程Y依赖工程Z, 工程Y的所有者可以标记工程Z作为一个可选依赖, 使用optional标签. 当工程X依赖工程Y时, X将只依赖Y, 而不依赖Z. X的所有者也可显式地添加Z作为一个依赖. 这有助于将可选依赖理解为默认的排除依赖.

Dependency Scope

依赖范围用于限制一个依赖的传递性, 也用于影响各种构建任务使用到的类路径classpath.

有6种可用范围:

(1) compile. 编译依赖范围. 这是默认的范围, 如果没有指定范围, 默认使用之. 在一个工程的所有类路径中, 编译依赖都有效. 包括:编译, 测试, 运行三种classpath.   此外, 这些依赖会扩散至依赖项目中.

典型例子: spring-core, 在编译\测试\运行时都需要这种依赖.

(2) provide. 已提供依赖范围. 与编译依赖范围很像, 但意味着你期望JDK或者一个容器来提供运行时依赖.  例如, 当构建一个JAVA企业级的WEB应用时, 你将设置基于servlet api和相关的java ee api的provide依赖, 但在运行项目时, 因为web容器提供这些类, 就不需要maven重复地引入了.. 这个范围只对编译和测试classpath有效, 且不会传递.

典型例子: servlet-api, 在运行项目时由容器提供.

(3) runtime. 运行时依赖范围. 这种范围在编译期不需要, 而运行时需要. 在运行和测试classpath中生效, 而编译classpath不生效.

典型例子: JDBC驱动的实现. 项目主代码的编译只需要JDK提供的JDBC接口, 在执行测试或运行时才需要具体实现.

(4) test. 测试依赖范围. 应用的正常使用时不需要, 只在测试时的编译和运行阶段生效.

典型例子: JUnit, 只有在编译测试代码和运行测试时才需要.

(5) system. 系统依赖范围. 类似于provided, 期望由你来显式提供JAR. 构件总是有效的, 而不需要去仓库中查找. 通过 systemPath元素来显式指定依赖文件的路径, 可以引用环境变量. 不需要maven仓库解析, 往往与本机系统绑定, 可能造成构建的不可移植, 谨慎使用.

(6) import. 导入依赖范围. (only available in Maven 2.0.9 or later) 只用于依赖是一个POM时.  指定的POM应该被当前工程的POM文件中的<dependencyManagement>节中定义的依赖关系取代. 因为他们被替代了, import依赖不会影响一个依赖的传递性. 也就是说, 对3种classpath没有实际影响.

每一种范围, 除了import, 以不同的方式影响着依赖传递性. 如下表所示.

Dependency Management

依赖管理部分是集中了依赖信息的机制. 当你有一组继承自同一父工程的子工程时, 可以把所有依赖信息都放到共同POM中, 而在子POM中简单地引用这些工程.

但存在一个问题: 依赖是会被继承的. 我们可以确定多个子模块中可能包含了若干依赖, 但无法确定某个子模块一定需要全部的依赖.

maven提供的 dependency management元素 既让子模块依赖父模块的配置, 又能保证子模块依赖使用的灵活性. 在dependencyManagement元素下的依赖声明不会引入实际的依赖, 不过它能约束 dependencies下的依赖使用.

(1) 将完整的依赖声明包含在父POM中, 子模块只需要配置简单的groupId和artifactId就能获得对应的依赖信息. 引入正确的依赖.

好处: 父POM中使用dependencyManagement声明依赖能够统一项目范围中依赖的版本, 当依赖版本在父POM声明之后, 子模块就无须声明 , 也不会发生多个子模块中版本不一致的情况. 有助于降低依赖冲突的几率.

注意, 如果子模块不声明依赖的使用, 即使该依赖声明在父POM的dependencyManagement中, 也不会产生任何实际效果. ---灵活性.

给出2个POM, 它们继承自同一父工程.

这两个示例POM共享了一个共同的依赖, group-a:artifact-b:1.0.

上述工程的依赖可以合并到父POM中, 然后这两个子POM就可以简化:

注意: 在这些依赖引用中, 要特别指定<type>元素. 因为, 从dependencyManagement部分匹配一个依赖引用 的最小信息集实际上是:{groupId, artifactId, type, classifier}. 在很多情况下,如果没有指定的话, 这些依赖将指向jar构件.

因为默认的type是jar, 而classifier是null, 所以我们可以使用 {groupId, artifactId} 作为标识的最小集合. 当type不是jar时, 需要特别指出.

(2) 在依赖传递中控制构件的版本.

上例中, project B继承自project A.

dependency标签会被自动继承,  而dependencyManagement标签不会.

在子项目中的dependency中引入a, c 时, 可以指定版本和范围, 由于依赖调解, 会覆盖父POM中的定义.

注意, b 在父项目中定义了, 如果它在a, c中的pom中被引用的话, 就会使用该定义.

而d 在子项目中的dependencyManagement中定义的, 如果d 在a或c中引用 , 那就会使用这个定义, 因为依赖管理优先于依赖调解, 也因为当前pom的声明优先于父pom的声明.

Importing Dependencies

The features defined in this section are only available in Maven 2.0.9 or later.

前面提到的import依赖范围只有在dependencyManagement元素下才有效果. 使用该范围的依赖通常指向一个POM, 作用是将目标POM中的dependencyManagement配置导入并合并到当前POM的dependencyManagement元素中.

上图中的project B与前一节中的示例的区别在于, 本例没有继承工程A, 而是通过import依赖范围, 在dependencyManagement部分导入工程A中的dependencyManagement内容, 除了d以外. 因为在本例的dependencyManagement中也有定义了d.

上例中, Z导入了X,Y的依赖管理. 注意到X和Y都有依赖a, 且两者的版本不同. 这里将使用X中的版本, 因为X是先定义的, 并且Z中没有定义a.

import是非常有效的, 当用于定义一个多项目构建的相关构件库时. 一个工程使用一个或多个这些库里的构件是非常常见的. 然而,有时很难保持工程中使用的构件版本同步. 因为版本号分布在整个库中. 下面的模式阐述了 一个BOM如何创建并用于其他工程.

工程的根是BOM pom. 它定义了所有构件的版本号. 其他使用了该库的工程应该在它们自己的POM的dependencyManagement部分中导入.

父子工程使用BOM pom作为它的父亲. 它是一个正常的复合pom.

\

实际的项目pom:

下面的工程演示了如何在其他项目中使用上述库, 而不需要指定依赖工程的版本号:

注意:

不要试图导入一个定义在当前POM中的子模块的POM. 这样将会导致构建失败, 因为它无法定位该POM.

不要将导入的POM声明为父或祖父POM. 无法处理循环, 将会抛出一个异常.

当引用的构件所属的POM存在依赖传递时, 该工程需要在依赖管理中指定版本号. 如果不这样做, 将导致 一个构建失败, 因为构件可能没有指定的版本号. 这应该视为一个最佳实践, 在任何情况下. 因为它保证了构件的版本变来变去的.

System Dependencies

范围为 system 的依赖, 总是有效的, 不需要到仓库中搜索. 它们通常用于告诉maven, 哪些依赖由jdk 或vm提供. 典型应用是JDBC标准扩展, 或JAAS.

Reference

http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Transitive_Dependencies

<Maven实战>

Maven-Dependency Mechanism的更多相关文章

  1. Maven错误Failed to read artifact descriptor for xxx:jar 和 missing artifact maven dependency

    可参考:http://stackoverflow.com/questions/6111408/maven2-missing-artifact-but-jars-are-in-place http:// ...

  2. lib目录和maven dependency目录的jar包冲突

    用eclipse时新建项目时,会在lib目录下自动生成一些jar包,然后又在pom.xml文件中添加了依赖,导致lib下的jar包和maven dependency目录下的jar包产生了冲突.刚开始r ...

  3. Maven Dependency Scope用法

    原帖地址:http://uule.iteye.com/blog/2087485 官方API描述 Dependency scope 是用来限制Dependency的作用范围的, 影响maven项目在各个 ...

  4. maven dependency的版本冲突问题

    在改造一个旧项目中,遇到各种问题. 旧项目有十多个模块,因为没有一个统一的父pom,它们对第三方的jar的版本没有统一. 虽然也存在公共的依赖模块,比如commons.util,但是,我们的模块中,有 ...

  5. [maven] dependency标签理解

    在maven pom.xml文件中最多的就是dependency标签,我们用maven管理我们项目的依赖.这篇文章简单介绍dependency标签内部各个子标签的意义. 下面是dependency标签 ...

  6. Adding a custom jar as a maven dependency

    Using maven in a Java project is great. It manages builds (as customized as you may need), execution ...

  7. Maven Dependency Scope

     官方API描述 Dependency scope 是用来限制Dependency的作用范围的, 影响maven项目在各个生命周期时导入的package的状态. 自从2.0.9后,新增了1种,现在有了 ...

  8. <Maven><Dependency><Conflict><Could not resolve>

    maven conflict solution: scenerio: Runtime Error: ``` java.lang.SecurityException: class "javax ...

  9. 15) maven dependency scope

    Dependency Scope Dependency scope is used to limit the transitivity of a dependency, and also to aff ...

  10. Maven - dependency那些事儿

    身边有几位刚使用Maven的同学表示——在一个叫"pom.xml"的文件里声明一个依赖就不用去手动添加jar了,感觉这东西和自己手动管理依赖没太大区别. 当然,并不是这样,在此记录 ...

随机推荐

  1. c#数据库乱码

    1.sql连接语句加charset=utf8: 2.不要使用odbcConnection. 在由utf8改为latin1时候,需要修改的地方: 1.连接数据库语句中的charset: 2.在sql语句 ...

  2. 【IdentityServer4文档】- 贡献

    贡献 我们非常乐于接受社区贡献,但您应遵循一些指导原则,以便我们可以很方便的解决这个问题. 如何贡献? 最简单的方法是打开一个问题并开始讨论.然后,我们可以决定如何实现一个特性或一个变更.如果您即将提 ...

  3. udf.dll 源码

    一点关于UDF的发散思路 Author:mer4en7y Team:90sec 声明:UDF源码作者langouster 相信各位牛对UDF都不会陌生,看论坛叶总共享了一份UDF源码,以前一直没看过, ...

  4. 大型网站架构演化(六)——使用反向代理和CDN加速网站响应

    随着网站业务不断发展,用户规模越来越大,由于中国复杂的网络环境,不同地区的用户访问网站时,速度差别也极大.有研究表明,网站访问延迟和用户流失率正相关,网站访问越慢,用户越容易失去耐心而离开.为了提供更 ...

  5. 软工网络15团队作业4——Alpha阶段敏捷冲刺-4

    一.当天站立式会议照片: 二.项目进展 昨天已完成的工作: 完成程序副界面的设计与信息的输入统计 明天计划完成的工作: 日期等细致信息的处理 工作中遇到的困难: 对微信小程序开发的代码构成有了一些了解 ...

  6. deep learning3

    9.3.Restricted Boltzmann Machine (RBM)受限玻尔兹曼基 假设有一个二部图,每一层的节点之间没有链接,一层是可视层,即输入数据层(v),一层是隐藏层(h),如果假设所 ...

  7. Swift学习与复习

    swift中文网 http://www.swiftv.cn http://swifter.tips/ http://objccn.io/ http://www.swiftmi.com/code4swi ...

  8. 【bzoj1304】[CQOI2009]叶子的染色 树形dp

    题目描述 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点( ...

  9. Python 源码剖析(二)【整数对象】

    二.整数对象 1.PyIntObject 2.PyIntObject 对象的创建和维护 3.Hack PyIntObject 1.PyIntObject PyIntObject的定义: [intobj ...

  10. Devc++编译系统分配给int多少字节

    我看的是<C语言程序设计>..谭浩强的PDF版 里面只讲了VC和TC 的,没有Devc++的..(我的是5.10版) 还有这是什么意思? 经过查阅我进行了这样的测试: 得到了这样的结果: ...