Java小白踩坑录 - 如何设计不用后期升级的客户端API?

简介: Java小白踩坑录 - 如何设计不用后期升级的客户端API?

image.png

最近小王比较烦,因甲方大爷的需求变更,提供给国企软件中引用的一个 jar 中的常量发生了变化,他们更新了 jar 包,但甲方将新 jar 包替换掉旧的 jar 包,现在系统出现执行异常!该国企限令必须尽快找到问题并解决掉!

为了防止信息泄露,我们模拟一下这个场景

publicclassBinaryCompatibilityTest {
publicstaticvoidmain(String[] args) {
System.out.println(DefineConstants.FIRST+" "+DefineConstants.SECOND+" "+DefineConstants.THIRD);
 }
}

其中 DefineConstants 来自甲方对乙方的引用

importcom.test.constants.Words;
publicclassDefineConstants {
privateDefineConstants() { }; // UninstantiablepublicstaticfinalStringFIRST=Words.FIRST;
publicstaticfinalStringSECOND=Words.SECOND;
publicstaticfinalStringTHIRD=Words.THIRD;
}

其中,Words 是引用的公用 jar 包。

image.png

类实现如下

packagecom.test.constants;
publicclassWords {
privateWords() {
 }; // UninstantiablepublicstaticfinalStringFIRST="the";
publicstaticfinalStringSECOND=null;
publicstaticfinalStringTHIRD="set";
}

原先打印结果为:

the null set

现在乙方小王修改了 jar 包后,代码变成了 package com.test.constants;

publicclassWords {
privateWords() {
 }; // UninstantiablepublicstaticfinalStringFIRST="physics";
publicstaticfinalStringSECOND="chemistry";
publicstaticfinalStringTHIRD="biology";
}

他将重新打包后的 jar 包传给甲方,让甲方在 tomcat 上替换原来的 jar 包,结果运行后打印的结果却为:

the chemistry set

小白百思不得其解。

反复确认了 jar 包是否正确,都是最新的 jar 包。

项目经理万般无奈之下,只好请出半退隐的技术大神扫地僧,并答应扫地僧 1w/d 的辛苦费。

老司机了解了情况后,很快就找到了原因,通过 jd-gui 反编译了代码给小白看:image.png替换了 jar 包后,DefineConstants 并没有被重新编译,导致 FIRST 和 THIRD 的结果没有发生改变,但因 SECOND 本身为 null,在编译期常量表达式(compile-time constant expression) [JLS15.28] 的精确定义中找到。它的定义太长了,就不在这里写出来了,但是理解这个程序的行为的关键是 null 不是一个编译期常量表达式。运行时就会执行新的结果:chemistry

解决办法是

1.需要重新编译 DefineConstants 后,替换到新的 class

2.重新编译整个项目的打包文件,提供新的包文件替换旧的打包文件

第一个方案

优点: 线上改动小,影响小,速度快

缺点:只能解决当前问题,如果项目中还有别的地方引用这个变量,将还会出错。

第二个方案

优点:从根本上解决问题

缺点:线上影响稍微大一些。

小白可是个勤奋好学的家伙,项目搞定后请扫地僧吃饭喝酒,趁扫地僧酒醉,趁机问解决这个问题的诀窍,扫地僧喝迷糊后道出了本质:

原来 Java 考虑到升级的问题,有二进制兼容性规范。。。。。。。。。

因扫地僧喝的有点多,描述的不是很清楚,小王只记住了在 JSL 规范了有明确的描述。


目录
相关文章
|
1天前
|
Java API
Java一分钟之-Java日期与时间API:LocalDate, LocalDateTime
【5月更文挑战第13天】Java 8引入`java.time`包,改进日期时间API。`LocalDate`代表日期,`LocalDateTime`包含日期和时间。本文概述两者的基本用法、常见问题及解决策略。创建日期时间使用`of()`和`parse()`,操作日期时间有`plusDays()`、`minusMonths()`等。注意点包括:设置正确的`DateTimeFormatter`,考虑闰年影响,以及在需要时区信息时使用`ZonedDateTime`。正确使用这些类能提升代码质量。
10 3
|
1天前
|
Java API 数据处理
Java一分钟之-Stream API:数据处理新方式
【5月更文挑战第13天】Java 8的Stream API为集合操作提供了声明式编程,简化数据处理。本文介绍了Stream的基本概念、常见问题和易错点。问题包括并行流与顺序流的区别,状态改变操作的影响,以及忘记调用终止操作和误用`peek()`。理解并合理使用Stream API能提升代码效率和可维护性。实践中不断探索,将发掘更多Stream API的潜力。
11 3
|
1天前
|
安全 Java API
Java Stream API详解与使用
Java Stream API是Java 8引入的特性,提供函数式操作处理集合,支持链式操作和并行处理,提升代码可读性和性能。关键点包括:延迟执行的中间操作(如filter, map)和触发计算的终端操作(如collect, forEach)。示例展示了如何从Person列表过滤出年龄大于20的姓名并排序。使用Stream时注意避免中间操作的副作用,终端操作后Stream不能复用,以及并行操作的线程安全性。
|
2天前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的深度解析
【5月更文挑战第12天】本文将深入探讨Java 8中的两个重要新特性:Lambda表达式和Stream API。我们将从基本概念入手,逐步深入到实际应用场景,帮助读者更好地理解和掌握这两个新特性,提高Java编程效率。
40 2
|
3天前
|
移动开发 前端开发 NoSQL
ruoyi-nbcio从spring2.7.18升级springboot到3.1.7,java从java8升级到17(二)
ruoyi-nbcio从spring2.7.18升级springboot到3.1.7,java从java8升级到17(二)
44 0
|
3天前
|
安全 API 开发者
智能体-Agent能力升级!新增Assistant API & Tools API服务接口
ModelScope-Agent是一个交互式创作空间,它支持LLM(Language Model)的扩展能力,例如工具调用(function calling)和知识检索(knowledge retrieval)。它已经对相关接口进行了开源,以提供更原子化的应用LLM能力。用户可以通过Modelscope-Agent上的不同代理(agent),结合自定义的LLM配置和消息,调用这些能力。
|
4天前
|
Java API
【JAVA进阶篇教学】第三篇:JDK8中Stream API使用
【JAVA进阶篇教学】第三篇:JDK8中Stream API使用
|
5天前
|
网络协议 Dubbo Java
【网络编程】理解客户端和服务器并使用Java提供的api实现回显服务器
【网络编程】理解客户端和服务器并使用Java提供的api实现回显服务器
10 0
|
5天前
|
安全 Java 程序员
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
11 0
|
5天前
|
SQL Java 数据库连接
JDBC Java标准库提供的一些api(类+方法) 统一各种数据库提供的api
JDBC Java标准库提供的一些api(类+方法) 统一各种数据库提供的api
10 0