倚楼听风雨
淡看江湖路

阿里巴巴Java开发手册第六章-二方库依赖篇

今天无意中被孤尽大大以及《Maven实战》的原作者许晓斌大佬光临本博客,老四在知道这件事情是真的是受宠若惊,感觉十分幸福,觉得自己所有的努力都是值得的,建站不仅仅是为了为自己的学习之路做笔记,更是为了能帮助能看到这个网站的人一点点帮助,也觉得自己功德无量了。欣喜之余,今天发现自己写博客还是存在很多缺点和不足之处,比如文章的知识点解析的比较浅薄,这个跟老四学艺不精有关系,还会继续努力。另外博客有很多错别字,甚至将书籍的原作者名字都打错了,十分尴尬,以后会尽量改正这个缺点并经常对自己写过的文章做重复校验和修正,力求完美一些。

另外今天真的很感谢大佬孤尽和许晓斌老师,他们不仅和我交流,更是在评论中留下了更多的干货,再次抱拳,老四也会将这本书持续的分析完,然后不断的更新和补充,力求从中解读出更多的知识点,同时也约束自己更好的编码,设计项目,也希望能帮助更多为技术奋斗的人程序员/媛们,共勉!

下面附上许晓斌老师关于Maven补充的知识点链接,本地底下评论也可以看到。再次感谢一下前辈,做我们的指路人。

关于 maven 的依赖我补充一条现在看来很重要,但当时书里没写的最佳实践吧,那就是 BOM。

BOM:https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

spring boot uses BOM: https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-build-systems.html

JUnit 5 uses BOM: https://junit.org/junit5/docs/snapshot/release-notes/index.html#release-notes-5.2.0

老四也会尽量抽出时间学习BOM的知识点,到时候总结出文章发出来。就这样,撸起袖子使劲干吧!

—————-华丽的非分割线—————-

关于二方库,孤尽主要写的是关于Maven的一些使用规范,我们做Java的估计很难离开Maven项目管理,在这里推荐你们鼎鼎大名的一本书,那就是许晓斌的《Maven实战》。强烈建议你们买纸质版,读个一两遍,你会很深入的了解Maven。老四最近也在读第二遍,所以关于这章内容的解析,老四多半的附言都会参考这本书来说,希望能对看到这篇文章的人有所帮助。如果,你真的没钱,如果你真的舍不得,如果你真的只想看盗版的电子版,毕竟人各有志,老四也考虑了这部分人,文末会提供给你这本书的《Maven实战》pdf电子版(附带完整目录书签)下载,但是,我真的建议你买一本支持一下,毕竟,如今的时代,读书是成本最低但是是价值最大的一件事了。好了,废话少说,开始了。

1.[强制] 定义GAV(下面三个词的缩写,称之为Maven坐标)遵从以下规则:

— GroupID格式:com.{公司/BU}.业务线.[子业务线],最多四级。

说明:{公司/BU}

例如:alibaba/taobao/tmall/aliexpress等BU一级;子业务线可选。

正例:com.taobao.jstorm或com.alibaba.dubbo.register

— ArtifactID格式:产品线名-模块名。语义不重复不遗漏,先到中央仓库去查证一下。

正例:dubbo-client/fastjson-api/jstorm-tool

— Version:详细规定参考第二条。

老四附言:

孤尽讲了三个Maven坐标的必要元素,其实还有两个可选元素,分别是packaging和classifier。

  • groupId: 定义当前Maven项目隶属的实际项目。如孤尽所言,groupId不应该对应项目隶属的组织或公司。定义到业务层更好的解耦了项目层。
  • artifactId: 该元素定义实际项目中的一个Maven项目(模块),推荐的做法是使用实际项目名称作为artifactId的前缀,方便寻找实际构件。因为这样做,方便从一个lib文件夹中找到某个项目的一组构件。要不然你拿一个core-1.8.jar上谁家找去~~
  • version: 该元素定义Maven项目当前所处的版本。(SNAPSHOT、Release)
  • packaging: 该元素定义Maven项目的打包方式(war,jar,pom),可选,不定义的时候默认值为jar。
  • classfier: 该元素用来帮助定义构建输出一些附属构件。可选,附属构件与主构件相对应,比如javadoc,source都属于附属构件。
2.[强制] 二方库版本号命名方式: 主版本号.次版本号.修订号。
  • 主版本号: 产品方向改变,或者大规模API不兼容,或者架构不兼容升级。
  • 次版本号: 保持相对兼容性,增加主要功能特性,影响范围极小的API不兼容修改。
  • 修订号: 保持完全兼容,修复bug、新增次要功能特性等。

说明: 注意起始版本号必须为1.0.0,而不是0.0.1。正式发布的类库必须先去中央仓库进行查证,是版本号有延续性,正式版本号不允许覆盖升级。如当前版本: 1.3.3,那么下一个合理的版本号: 13.4或1.4.0或2.0.0。

老四附言:

首先明确一下版本管理和版本控制以及快照和发布版本的区别:

  • 版本管理: 指项目整体版本的演变过程管理,如从1.0-SNAPSHOT到1.0,再到1.1-SNAPSHOT。
  • 版本控制: 版本控制是指借助版本控制工具(SVN,GIT)追踪代码的每一个变更。
  • 快照(SNAPSHOT): 项目的开发过程中使用的版本,促进团队内部交流使用。
  • 发布版本: 当需要对外提供使用,我们应该保证构件稳定唯一,这类稳定的版本称为发布版。

发布版需要满足的条件:

  • 所有自动化测试应当全部通过。
  • 项目没有配置任何快照版本的依赖。
  • 项目没有配置任何快照版本的插件。
  • 项目所包含的代码已经全部提交到版本控制系统中。

基于孤尽所言,其实Maven的版本号也可以这样约定: <主版本>.<次版本>.<增量版本>-<里程碑版本>,例如1.3.4-beta-2.jar,表示该项目的第一个重大版本的第三次要版本的第四次增量版本的beta-2里程碑(往往指某一版本的里程碑)。主版本和次版本之间,以及次版本和增量版本之间用点号分隔,里程碑版本之前用连字号分隔。

3.[强制] 线上应用不要依赖SNAPSHOT版本(安全包除外)。

说明:不依赖SNAPSHOT版本是保证应用发布的幂等性。另外,也可以加快编译时的打包构建。

老四附言:

关于这一点说明,上一条关于发布版的规约已经说明了,这里说一下什么是幂等性: 指的是相同的参数重复执行总能获得相同的结果。这样的特性或者函数不会影响系统状态,也不用担心重复执行会对系统造成改变。

4.[强制] 二方库的新增或升级,保持除功能点之外的其他jar包仲裁结果不变。如果有改变,则必须明确评估和验证,建议进行dependency:resolve前后信息对比。如果仲裁结果完全不一致,则通过dependency:tree命令找出差异点,进行<excludes>排除jar包。

老四附言:

如果你使用Maven已经有一段时间了,应该知道Maven是使用传递性依赖的。例如某个项目依赖spring-core,而spring-core又依赖commons-logging,那么自然而然的根据传递性依赖这个项目也依赖commons-logging。附传递性依赖范围表:

阿里巴巴Java开发手册第六章-二方库依赖篇的图片-高老四博客 第1张

依赖调解两个原则:

  • 路径最优者优先
  • 路径相同的情况下,第一声明者优先。

排除依赖:项目A依赖于B,但是由于一些原因,不想引入传递性依赖C,而是显示地声明对于项目C特定版本的依赖,我们需要使用exclusions元素声明排除依赖。

5.[强制] 二方库里可以定义枚举类型,参数可以使用枚举类型,但是接口返回值不允许使用枚举类型或者包含枚举类型的POJO对象。

老四附言:

复习一下什么是POJO(Plain Ordinary Java Object):恩~~就是你经常写的javaBean~~

关于原因以及解释,这里引用孤尽在知乎的原回答,非常合理。

由于升级原因,导致双方的枚举类不尽相同,在接口解析,类反序列化时出现异常。Java中出现的任何元素,在Gosling的角度都会有背后的思考和逻辑(尽管并非绝对完美,但Java的顶层抽象已经是天才级了),比如:接口、抽象类、注解、和本文提到的枚举。枚举有好处,类型安全,清晰直接,还可以使用等号来判断,也可以用在switch中。它的劣势也是明显的,就是不要扩展。可是为什么在返回值和参数进行了区分呢,如果不兼容,那么两个都有问题,怎么允许参数可以有枚举。当时的考虑,如果参数也不能用,那么枚举几乎无用武之地了。参数输出,毕竟是本地决定的,你本地有的,传送过去,向前兼容是不会有问题的。但如果是接口返回,就比较恶心了,因为解析回来的这个枚举值,可能本地还没有,这时就会抛出序列化异常。

比如:你的本地枚举类,有一个天气Enum:SUNNY, RAINY, CLOUDY,如果根据天气计算心情的方法:guess(WeatcherEnum xx),传入这三个值都是可以的。返回值:Weatherguess(参数),那么对方运算后,返回一个SNOWY,本地枚举里没有这个值,傻眼了。

6.[强制] 依赖于一个二方库时,必须定义一个统一的版本变量,避免版本号不一致。

说明:依赖springframework-core、springframework-context、springframework-beans,他们都是同一版本。可以定义一个变量来保存版本:${spring.version},定义依赖的时候,引用该版本。

老四附言:

没啥可说的,这就跟你在Java中定义静态常量差不多一个意思。一处改动,全局都跟着改变,以防不测。

7.[强制] 禁止在子项目的pom依赖中出现相同的GroupId,相同的Aryifactid,但是不同的Version。

说明:在本地调试时会使用各子项目指定的版本号,但是若合并成一个war,则只能有一个版本号出现在最后的lib目录中。可能会出现线下调试是正确的,发布到线上却出故障的问题。

老四附言:

孤尽说的对~~

8.[推荐] 所有pom文件中的依赖声明放在<dependencies>语句块中,所有版本仲裁放在<dependenciesManagement>语句块中。

说明:<dependenciesManagement>里只是声明版本,并不实现引入,因此子项目需要显式的声明依赖,version和scope都读取自父pom。而<dependencies>所有声明在主pom的<dependencies>里的依赖都会自动引入,并默认被所有的子项目继承。

老四附言:

Maven 使用dependencyManagement 元素来提供了一种管理依赖版本号的方式。通常会在一个组织或者项目的最顶层的父POM 中看到dependencyManagement 元素。使用pom.xml 中的dependencyManagement 元素能让所有在子项目中引用一个依赖而不用显式的列出版本号。Maven 会沿着父子层次向上走,直到找到一个拥有dependencyManagement 元素的项目,然后它就会使用在这个dependencyManagement 元素中指定的版本号。

如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样当想升级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要一个一个子项目的修改 ;另外如果某个子项目需要另外的一个版本,只需要声明version就可。

PS:dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显式的声明需要用的依赖。

9.[推荐] 二方库不要有配置项,最低限度不要再增加配置项。

老四附言:

都是为了方便实用,别整一些乱七八糟的,直接一个jar包利人利己。

10.[参考] 为避免应用二方库的依赖冲突问题,二方库发布者应当遵循一下原则:
  • 精简可控原则。移除一切不必要的API依赖,只包含Service API、必要的领域模型对象、Utils类、常量、枚举等。如果依赖其他二方库,尽量是provided引入,让二方库使用者依赖具体版本号;无log具体实现,只依赖日志框架。
  • 稳定可追溯原则。每个版本变化都应该被记录,二方库由谁维护,源码在哪里,都需要能方便查到。除非用户主动升级版本,否则公共二方库的行为不应该发生变化。

老四附言:

在这里提一下什么是一方库、二方库、三方库以及provided的兄弟姐妹们。

  • 一方库:本工程中的各模块的相互依赖
  • 二方库:公司内部的依赖库,一般指公司内部的其他项目发布的jar包
  • 三方库:公司之外的开源库, 比如apache、ibm、google等发布的依赖

Maven的依赖范围:

  • compile 编译依赖范围。没有指定的话默认使用使用该依赖范围。
  • test 测试依赖范围。
  • provided 已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效,典型的例子就是servlet-api,运行时tomcat容器已经提供了。
  • runtime 运行时依赖范围。
  • system 系统依赖范围。慎用!!!
  • import 导入依赖范围,支持Maven2.0.9以上版本。只在<dependenciesManagement>元素下才有效果,使用该范围的依赖通常指向一个pom,作用是将目标pom中的<dependenciesManagement>配置导入并合并到当前pom的<dependenciesManagement>元素中。

阿里巴巴Java开发手册第六章-二方库依赖篇的图片-高老四博客 第2张

Mav实战高清PDF带目录标签文末自助获取下载。

更博不易,如果觉得文章对你有帮助并且有能力的老铁烦请赞助盒烟钱,点我去赞助。抱拳。

资源下载

隐藏内容:******,购买后可见!

下载价格:0 G币

您需要先后,才能购买资源

欢迎访问高老四博客(glorze.com),本站技术文章代码均为老四亲自编写或者借鉴整合,其余资源多为网络收集,如涉及版权问题请与站长联系。如非特殊说明,本站所有资源解压密码均为:glorze.com。

赞(11) 给你买杜蕾斯
本站原创文章受自媒体平台原创保护,未经允许不得转载高老四博客 » 阿里巴巴Java开发手册第六章-二方库依赖篇

开始你的表演 6

  1. #1

    许晓斌,而不是许小斌

    孤尽6年前 (2018-05-07)回复
    • 感谢指出错误,马上改正过来。话说孤尽是不可能光临到我的博客中来的吧?

      Glorze6年前 (2018-05-07)回复
      • 是他,还让我来看了

        许晓斌6年前 (2018-05-07)回复
        • 这个太狠了,如果是真的请您对我的文章点评几句,给出中肯的建议让鄙人更好的学习,知道自己的优缺点。如果是闹着玩的我也非常感谢您,令我这个小博客有那么一丝温暖的氛围。抱拳

          Glorze6年前 (2018-05-07)回复
          • 哈哈,没闹你玩啊,真人,关于 maven 的依赖我补充一条现在看来很重要,但当时书里没写的最佳实践吧,那就是 BOM。

            BOM:https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

            spring boot uses BOM: https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-build-systems.html

            JUnit 5 uses BOM: https://junit.org/junit5/docs/snapshot/release-notes/index.html#release-notes-5.2.0

            许晓斌6年前 (2018-05-07)
          • 刚才在群里面确认了一下,实在是太激动了。很抱歉在博客中写错了您的名字,已经改正过来了。也再次感谢您这次回复又为大家提供了新的知识点,发现您现在已经是阿里的技术专家了,很喜欢您的书,正在上班的我已经有点语无伦次了。感谢感谢。希望您以后对小站的文章不吝批评指点,老四虚心接受指教,抱拳抱拳,要是能在支付宝大楼碰到您二位就更开心了。

            Glorze6年前 (2018-05-07)

觉得文章有用就打赏一下老四,鼓励我更好的创作

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏

登录

找回密码

注册