Maven-Optional Dependencies & Dependency Exclusion
本文讨论可选依赖和排除依赖. 帮助用户理解它们是什么, 如何使用, 它们如何工作, 以及什么时候使用它们最合适. 本文也将解释为什么排除是基于单个依赖的, 而非POM级别的.
Optional Dependencies
可选依赖用在不能真正地将一个项目划分为多个子模块时. 一些依赖只在该项目中的某些特性中使用, 并且如果这些特性没有使用到的话, 这些依赖就不需要. 最理想的情况, 这样的特性会被划分到一个依赖于核心功能工程的子模块, 这个新子模块将只有非可选依赖, 因为一旦你决定使用该子模块的功能, 你就会需要这些依赖.
然而, 如果该项目无法划分, 这些依赖就需要被声明为可选的. 如果一个用户想要使用和一个可选依赖相关的功能, 他们需要在自己的工程里声明那个可选依赖. 这并不是处理这种情况的最清晰的方式.. 但可选依赖和依赖排除都是 stop-gap 方案.
Why use optional dependencies?
声明可选依赖不仅仅在节省内存空间问题上很重要. 当一个用户使用一个工程时, 控制实际需要的依赖列表非常重要. 因为这些jar包可能会最终放入一个WAR, EAR, EJB等等. 包含了错误的jar包, 可能会违反许可协议, 引起路径问题等等.
How do I use the optional tag?
声明一个可选依赖, 只需要在你的依赖声明中简单地设置 <optional> 标签为 true. 如下例所示:

How do optional dependencies work?
Project-A -> Project-B
如果 project A 依赖于 project B, 当A将B声明为可选依赖时, 这个关系就确定下来了. 这就像一个正常的构建, B将会被添加到它的类路径里.
Project-X -> Project-A
但当另一个工程 project X 将工程A声明为它的依赖时, 可选依赖就发挥效用了. 你会发现, 工程B没有被包含到X的类路径中. 你需要在POM中直接声明B, 才能将它包含到X的类路径中.

Example
假设有一个工程名为X2, 它和Hibernate有相似的功能, 支持很多种数据库驱动, 比如mysql, postge, oracle等. 构建X2需要所有这些依赖, 但你的项目未必. 所以, 将这些依赖声明为可选的对X2来说是非常实用的, 这样无论何时你的项目声明了X2作为一个直接依赖, X2支持的所有驱动就不会自动地包含到你的工程的类路径里, 你需要直接声明你需要的数据库驱动.
[注意] 在理想情况下, 不应用使用可选依赖. 在面向对象设计中, 有个单一职责性原则, 意指一个类应该只有一项职责, 而不是糅合太多功能. 这个原则在规划maven项目时也同样适用. 上例中, 更好的做法是为mysql和postgreSQL分别创建一个maven项目, 基于同样的groupId分配不同的artifactId. 在各自的pom中声明对应的jdbc驱动依赖, 不使用可选依赖. 用户根据需要选择使用. 由于传递性依赖的作用, 就不用再声明jdbc驱动依赖了.
Dependency Exclusions
由于maven 2.x的依赖传递规则, 很有可能你的项目类路径中包含了一些不想要的依赖. 比如说, 你的项目依赖的那些工程可能没有正确地声明他们的依赖集合. 为了应对这个特殊的场景, maven2.x提出了依赖排除的概念. 排除是针对POM中的一个特定的依赖设置的, 以一个特定的groupId和artifactId为标识. 如果你声明了排除依赖, 当你构建你的工程时, 该构件就不会被添加到你的工程的类路径中.
How to use dependency exclusions
我们在pom的<dependency>部分添加<exclusions>标签.

How dependency exclusion works and when to use it ( as a last resort! )
如下图所示. 工程A同时依赖于B,C. 而工程B又依赖于D. 默认情况下, A的类路径会包含: B, C, D, E, F.
如果我们不需要使用工程D, 同时不想把它的依赖添加到A的类路径中, 因为我们已知D的某些依赖, 比如说E, 在仓库中找不到了. 而你又不需要工程B中依赖于工程D的那部分功能. 在这种情况下, B的开发者可能会提供一个关于D的可选依赖.
然而!!! 他们没有提供!!! 作为最后的手段, 你依然可以选择在你这一侧把不想要的依赖排除掉.


如果我们将工程A发布到一个仓库, 并且工程X声明一个关于A的普通依赖, 那么D还会被排除在类路径之外吗?
答案是会. 工程A已经声明了它不需要工程D就可以运行, 所以这会产生一个传递的依赖.
现在, 考虑工程X依赖于Y. 工程Y也有一个关于B的依赖, 且它确实需要由工程D支持的特性. 因此, 在它的依赖列表里不会出现排除D的情况. 它也可能提供一个额外的仓库, 在那里我们可以处理工程E. 在这种情况下, 工程D不是全局排除就非常重要了, 因为它是Y的一个合法依赖.
Why exclusions are made on a per-dependency basis, rather than at the POM level
主要是为了确保依赖关系图是可预知的, 避免排除了不应排除的依赖. 如果你需要排除, 你应绝对确定你引入的哪个依赖带来了不必要的依赖传递.
Reference
http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html
<Maven实战>
Maven-Optional Dependencies & Dependency Exclusion的更多相关文章
- maven可选依赖(Optional Dependencies)和依赖排除(Dependency Exclusions)
我们知道,maven的依赖关系是有传递性的.如:A-->B,B-->C.但有时候,项目A可能不是必需依赖C,因此需要在项目A中排除对A的依赖.在maven的依赖管理中,有两种方式可以对依赖 ...
- Maven Optional & Exclusions 使用区别
Optional和Exclusions都是用来排除jar包依赖使用的,两者在使用上却是相反. Optional定义后,该依赖只能在本项目中传递,不会传递到引用该项目的父项目中,父项目需要主动引用该依赖 ...
- Maven optional关键字透彻图解
写在前面 本来想写一篇「如何自定义Spring Boot Starter」,但是为了更好理解 Starter 的一些设计理念和其中的关键点,所以提前将一些细节内容单独提取出来讲解说明 在 Maven ...
- maven坐标Dependencies和Exclusions详解
1.概念介绍 Dependencies:是可选依赖(Optional Dependencies) Exclusions:是依赖排除(Dependency Exclusions) 2.Dependenc ...
- Maven Optional & Exclusions使用区别
Optional和Exclusions都是用来排除jar包依赖使用的,两者在使用上却是相反. Optional定义后,该依赖只能在本项目中传递,不会传递到引用该项目的父项目中,父项目需要主动引用该依赖 ...
- 【dependencyManagement版本管理】dependencies.dependency.version is missing
maven 的gav的v(版本问题) 报错dependencies.dependency.version is missing 出现的场景 一个项目中有多个模块 父模块中出现dependencies. ...
- Maven中<dependencies>节点和<dependencyManagement>节点的区别 转
以前一直没有在意,今天建立maven工程的时候在<dependencyManagement>节点下加入了junit依赖,结果在dependency Graph中没有发现junit的依赖关系 ...
- 'dependencies.dependency.(groupId:artifactId:type:classifier)' must be unique
2016-10-09 23:14:43.177 DEBUG [restartedMain][org.springframework.core.type.classreading.AnnotationA ...
- 解决eclipse svn 转 maven web 项目中遇到找不到maven managed dependencies的问题
我们在使用eclipse从svn上check项目下来,然后转成maven web 项目的时候,经常会遇到一个问题,就是找不到maven依赖(maven managed dependencies),从而 ...
随机推荐
- windows编程了解
文章:浅谈Windows API编程 (这个经典)
- [zt]手把手教你写对拍程序(PASCAL)
谁适合看这篇文章? ACMERS,OIERS或其它参加算法竞赛或需要算法的人 对操作系统并不太熟悉的人 不会写对拍的人 在网上找不到一个特别详细的对拍样例的人 不嫌弃我写的太低幼的人 前言 在NOIP ...
- LintCode-8.旋转字符串
旋转字符串 给定一个字符串和一个偏移量,根据偏移量旋转字符串(从左向右旋转) 样例 对于字符串 "abcdefg". offset=0 => "abcdefg&qu ...
- iOS- 优化与封装 APP音效的播放
1.关于音效 音效又称短音频,是一个声音文件,在应用程序中起到点缀效果,用于提升应用程序的整体用户体验. 我们手机里常见的APP几乎都少不了音效的点缀. 显示实现音效并不复杂,但对我们App很 ...
- Swift-重写(Override)
子类可以为继承来的实例方法(instance method),类方法(class method),实例属性(instance property),或附属脚本(subscript)提供自己定制的实现(i ...
- Ubuntu编译内核树
什么是内核树?刚开始我也没弄明白,通过这几天的学习,有所感悟,就说说我的理解吧!从形式上看,内核树与内核源码的目录结构形式是相同的,都是由各个层次的文件目录结构组成,但是其中的具体内容肯定是不同的.从 ...
- <hx>标签 字体自动加粗 自动换行
<hx>标签 字体自动加粗 自动换行
- mac终端命令-----常规操作
OSX 的文件系统 OSX 采用的Unix文件系统,所有文件都挂在跟目录 / 下面,所以不在要有Windows 下的盘符概念. 你在桌面上看到的硬盘都挂在 /Volumes 下. 比如接上个叫做 US ...
- Swift学习与复习
swift中文网 http://www.swiftv.cn http://swifter.tips/ http://objccn.io/ http://www.swiftmi.com/code4swi ...
- 【bzoj3036】绿豆蛙的归宿 期望dp
题目描述 随着新版百度空间的下线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿. 给出一个有向无环的连通图,起点为1终点为N,每条边都有一个长度.绿豆蛙从起点出发,走向终点.到达每一个顶点时,如 ...