转载声明
本文大量内容系转载自网络,有删改,并参考其他文档资料加入了一些内容:
- Maven optional关键字透彻图解
- 作者:日拱一兵
- 出处:cnblos
1 背景
在 Maven pom.xml 中,你经常会看到依赖项中有类似下面的代码:
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
这里的<optional>true</optional>
是什么意思呢?
2 optional 关键字的奥秘
2.1 例子
老规矩,画个图说明问题:
-
由于 project C 使用到了两个来自 project A 的类 (OptionalFeatureAClass) 和 project B 的类 (OptionalFeatureBClass). 如果 project C 没有依赖 packageA 和 packageB,那么编译将会失败。
-
project D 依赖 project C,但是对于 project D 来说,类 (OptionalFeatureAClass) 和类 (OptionalFeatureBClass) 是可选的特性,所以为了让最终的 war/ejb package 不包含不必要的依赖,使用
<optional>
声明当前依赖是可选的, 默认情况下也不会被其他项目继承(好比 Java 中的 final 类,不能被其他类继承一样) -
如果 project D 确实需要用到 project C 中的 OptionalFeatureAClass 怎么办呢?那我们就需要在 project D 的 pom.xml 中显式的添加声明 project A 依赖,继续看下图:
-
Project D 需要用到 Project A 的
OptionalFeatureAClass
,那么需要在 Project D 的 pom.xml 文件中显式的添加对 Project A 的依赖
2.2 小结
到这也就很好理解为什么 Maven 为什么要设计 optional 关键字了。
假设一个关于数据库持久化的项目(Project C), 为了适配更多类型的数据库持久化设计,比如 Mysql 持久化设计(Project A) 和 Oracle 持久化设计(Project B),当我们的项目(Project D) 要用的 Project C 的持久化设计,不可能既引入 mysql 驱动又引入 oracle 驱动吧,所以我们要显式的指定其中一个,就是这个道理了。
3 实际案例
在spring-boot-actuator pom.xml
文件中,有超过 20 个依赖是 optional
因为 Spring Boot 不可能将没必要的依赖也打包到你最终的 jar package 中,所以用到spring boot actuator
的项目最终生成的 jar中不会包含这 20 多个依赖 jar,如果你要用到哪一个,显式的加入到你的项目就好了
自定义 Spring Boot Starter 也是这个策略,因为 starter 是包含特定功能为其他项目服务用的,类似本文的 Project C 的中介角色,到这里你理解 optional 的奥秘了吗?
4 反向应用
如果 Project C 引入的依赖没有加<optional>true</optional>
,Project D 又需要依赖 Project C,但只用到 Project A 的类怎么办呢?Maven 也是有解决办法的,使用 exclusion 关键字,不多说,上一段代码就懂了:
<dependencies>
<dependency>
<groupId>top.dayarch.demo</groupId>
<artifactId>Project-C</artifactId>
<exclusions>
<exclusion>
<groupId>top.dayarch.demo</groupId>
<artifactId>Project-B</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
5 总结
到这里,在你今后设计功能性依赖时,你应该明白怎样设计依赖关系了, 我这里推荐使用 optional 的形式,简单来说,你设计的依赖什么菜都有,想吃什么菜自己 报菜名
就好。