OpenJDK 21 已经发布半年有余,在这个版本中, Generational ZGC 也一起发布了。在 ZGC | What’s new in JDK 16 中, Per Lidén 宣称,将 ZGC 的最大停顿时间从 10ms 降低到了 1ms。再加上 JVM GC 性能测试(二):递增流量 和 JVM GC 性能测试(三):真实流量 文中,GenZGC 的惊艳表现,这些种种先进技术,着实充满诱惑,忍不住想吃口螃蟹 🦀。这篇文章,D瓜哥就来分享一下,自己在升级 OpenJDK 21 中的一些经验。
本文仅介绍升级 OpenJDK 的相关内容,ZGC 原理等会专门撰文介绍。
在做新需求开发或者相关系统的维护更新时,尤其是涉及到不同系统的接口调用时,在可维护性方面,总感觉有很多地方差强人意。一些零星思考,抛砖引玉,希望引发更多的思考和讨论。总结了大概有如下几条建议:
在接口注释中加入接口文档链接
将调用接口处写上被调用接口文档链接
将接口源代码发布到私服仓库
对于状态值常量,优先在接口参数类或者返回值类中定义
如果使用 Map 对象作为传输载体,要提供 Key 值定义常量
针对 Map 返回值,可以考虑使用将 Map 转化成对象
尽可能简化接口依赖
只传递必要字段,尽量避免大而全的接口
将接口的参数和返回值原始数据打印到日志中
将 RPC 接口的类名及方法打印到日志中
核心思想:以人为本,就近原则,触手可及
下面,D瓜哥对每一条建议做一个详细说明。
1. 在接口注释中加入接口文档链接 在做接口开发时,无论是对自有接口的升级改造,还是针对外部接口的从头接入,都涉及到接口文档。不同之处是,前者的工作重点是书写或者更新接口文档;而后者是根据接口文档开发合适的接入代码。但是,经常遇到的一个麻烦是,找不到接口文档。在组内需要找老同事询问;如果是跨部门,还需要两层甚至三层的进行转接,非常麻烦。
D瓜哥认为,在这种情况下,为了方便大家维护,最好的办法就是将接口文档链接直接放在代码注释中,这样后续维护的人员,直接就可以点击链接直达接口文档,简单方便高效。如果是新建的接口,就可以先创建一个空文档,把链接放在注释中,后续再书写文档内容。如果是维护已有接口,可以在维护时,将缺失的链接加入到注释中,自己方便,也方便其他人进行后续的维护更新。这样,在循序渐进的过程中,逐步就可以把文档链接补充到代码中,方便维护代码,也同步更新文档。
在 制定组织内 Maven BOM 的一些规范 中,D瓜哥 介绍了一些组织内指定 Maven BOM 的一些规范。根据这些规范,D瓜哥 创建并维护了部门内部的 Maven BOM。今年,要求对部门内的陈旧依赖做一些升级工作。所以,在 关于升级 Spring 等依赖的一些经验 中介绍了一些升级开源依赖的经验;在上一篇文章 升级 Maven 插件 中介绍了升级 Maven 插件的一些注意事项。
D瓜哥一直坚持“机器可以干的事情,就应该交给机器干”。对于依赖管理,Maven Enforcer 插件就可以对依赖做必要的检查,所以,在 使用 Maven Enforcer 插件检查依赖 中,介绍了如何使用 Apache Maven Enforcer 来管理依赖。由于要维护部门内部的 Maven BOM,同时由于版本控的特质,所以,需要时长检查依赖升级情况。原来都是手动检查,需要一个一个去搜索各个依赖,不仅费时费力,而且还低效。最近,Maven 有一个插件可以胜任这个工作,它就是: Versions Maven Plugin。
依赖检查 Versions Maven Plugin 支持两种配置方式:
D瓜哥在 关于升级 Spring 等依赖的一些经验 中,介绍了一些升级 Spring 等依赖的一些经验。在 升级 iBATIS/MyBATIS 对处理 DuplicateKeyException 的影响 中,分析了升级 iBATIS/MyBATIS 对处理 DuplicateKeyException 异常的影响。在升级中,还遇到一些 Maven 插件相关的问题。这里也分享出来,希望对大家有所帮助。
Properties 文件编码错误 在升级过程中,遇到过 Properties 文件编码错误的问题。可以通过配置对应的编码来解决这个问题。配置如下:
<!-- D瓜哥 · https://www.diguage.com --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.3.0</version> <configuration> <propertiesEncoding>ISO-8859-1</propertiesEncoding> </configuration> </plugin>
在 关于升级 Spring 等依赖的一些经验 中,分享了一些开源依赖的升级经验。部分小伙伴质疑升级 iBATIS/MyBATIS 会影响对 DuplicateKeyException 异常的处理。这篇文章就从源码分析/代码更新的就角度来分析一下升级相关依赖是否会对 DuplicateKeyException 异常的处理带来实质性的影响。
由于主要的技术栈涉及 MySQL 驱动、iBATIS、MyBATIS、Spring 周边等。所以,本文仅分析涉及的这些依赖。
D瓜哥使用 MySQL: Employees Sample Database 搭建了一个 Spring + MyBATIS + MySQL Connector/J 的测试环境。连续插入两条一样的数据,单步调试,在 com.mysql.jdbc.MysqlIO#sendCommand 方法中,就可以观察到如下异常:
图 1. MySQL Error 1062 从这里可以明显看出,MySQL 驱动返回的异常中, venderCode 编码是 1062。
在 关于升级 Spring 等依赖的一些经验 中介绍了 D瓜哥在升级项目依赖时,遇到的一些问题以及一些需要注意的地方。但是,这里还存在一个问题:各个依赖的版本依然散落在各个项目中;升级依赖,需要在所有项目中,把所有相关项目的依赖都巴拉一下,费时费力。解决这个问题的一个比较好的办法是制定一个组织内部的 Maven BOM,集中管理相关依赖的版本。这样升级的时候,还需要修改 BOM 的版本号即可。
Maven BOM 介绍 BOM(Bill of Materials)是由 Maven 提供的功能,它通过定义一整套相互兼容的 jar 包版本集合,使用时只需要依赖该BOM文件,即可放心的使用需要的依赖 jar 包,且无需再指定版本号。
一些基本原则 Spring & Spring Boot 是 Java 生态中,全世界广泛使用的开发框架,在各种场景中都经受过考验。所以,Spring & Spring Boot 选择的 Jar 在稳定性和兼容性方面都有保证。另外,Spring Boot 本身就集成了非常非常多的依赖,并为此创建了一个网页 Spring Boot Dependency versions 来说明它集成的依赖及版本。故而,可以选择以 Spring Boot 为底本,来制作自己的 BOM。
如果不需要 Spring 相关依赖,可以将 Spring 相关依赖删除掉,然后在其之上增加组织内部依赖而创建自己的 BOM。
如果需要 Spring 相关依赖,那么直接继承
到公司后,熟悉了一些项目后,发现大部分项目的依赖都比较陈旧,比如某些项目还在使用 Spring 3.x 的版本。所以,在进行需求开发时,也顺手把一些项目的依赖给升级了一下。周五,一个小伙伴问我关于升级 Spring 的经验。正好趁此机会,把一些经验总结一下。
下面的描述以 Java 8 为准,没有在其他版本 Java 上试验过。参考时,请慎重。描述的原则如下:
尽量选择还在维护中的版本,而不是已经 End of Life 的过时版。这样有问题可以及时反馈并得到修复。
Java 8 是目标版本,所以,一定要兼容 Java 8。
Spring Framework 升级 Spring Framework 从 3.2.6.RELEASE 开始提供 BOM。可以利用 BOM 简化 Spring 依赖声明:
<!-- D瓜哥 · https://www.diguage.com --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-framework-bom</artifactId> <version>5.3.25</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
最近公司项目要对一些内部依赖做集中升级。为此,D瓜哥发布了一个 BOM(BOM stands for Bill Of Materials),用于规范项目依赖及版本。
但是升级后,效果不理想,检查发现还是有不少依赖的版本依然不符合要求。经同事提醒,可以使用 Apache Maven Enforcer 来做规范检查,测试一下效果确实不错。
将 Apache Maven Enforcer 和 Extra Enforcer Rules 的文档大致巴拉了一遍之后,根据项目的实际情况,挑选出来可用规则如下:
比较有用的几个规则 bannedDependencies – 排除不需要的依赖,引入需要的依赖。
banDuplicatePomDependencyVersions – 防止依赖重复声明。
dependencyConvergence – 确保所有依赖收敛到相同的版本。也可以考虑加入。
reactorModuleConvergence – 多模块开发时,确保父子模块的版本是一致的。
requireJavaVersion – 检查 JDK 的版本
requireMavenVersion – 检查 Maven 的版本
requireReleaseVersion – 这个可以通过激活生产环境的 profile 来启用该规则,保证发布的不是快照版。
requireUpperBoundDeps – 确保直接引用的依赖不比间接解析出来的依赖版本低。感觉这个也挺有用,但是使用方式还没搞清楚。实例有些模糊。
banDuplicateClasses – 检查重复类定义。可以避免一些特殊情况。
requirePropertyDiverges – 确保项目定义的属性与依赖中包含的属性不重复。
enforceBytecodeVersion – 确保使用的字节码版本不高于指定版本。
banCircularDependencies – 确保没有循环依赖。
requireEncoding – 指定项目字符集。
D瓜哥在前面的文章 使用 Hugo 搭建博客 中介绍了如何用 Hugo 搭建个人博客。部门准备系统地整理一下各个小组的文档。恰好 D瓜哥 对写文档非常感兴趣,正好写个材料分享一下血泪经验。
编辑进化之路 第一代:WordPress 缺点:写作和排版割裂,排版耗时且繁琐
第二代:MarkDown 缺点:方言众多,工具链不够完整。
现在已经改观很多。
第三代:AsciiDoc
我们面临的真正挑战是找到深层次的模型,这个模型不但能够捕捉到领域专家的微妙的关注点,还可驱动切实可行的设计。我们的最终目的是开发出能够捕捉到领域深层含义的模型。
要想成功地开发出实用的模型,需要注意以下 3 点:
复杂巧妙的领域模型是可以实现的,也是值得我们去花费力气实现的。
这样的模型离开不断的重构是很难开发出来的,重构需要领域专家和热爱学习领域知识的开发人员密切参与进来。
要实现并有效地运用模型,需要精通设计技巧。
重构就是在不改变软件功能的前提下重新设计它。
自动化的单元测试套件能够保证对代码进行相对安全的试验。
设计模式重构 — 为实现更深层模型而进行的重构。
代码细节重构
简称为“领域模型重构”。 学习以更高维度去看待问题。
《重构》一书中所列出的重构分类涵盖了大部分常用的代码细节重构。这些重构主要是为了解决一些可以从代码中观察到的问题。
领域模型会随着新认识的出现而不断变化,由于其变化如此多样,以至于根本无法整理出一个完整的目录。
建模和设计都需要你发挥创造力。
对象分析的传统方法是先在需求文档中确定名词和动词,并将其作为系统的初始对象和方法。
事实上,初始模型通常都是基于对领域的浅显认知而构建的,既不够成熟也不够深入。