Java17稳妥升级计划

近年来,微服务、容器化、云原生等基础设施或架构设计不断更新迭代,对Java技术体系带来新的挑战,同时也迫使Java加快了更新步伐以适应新的环境与需求。

目前许多企业仍将Java 8作为首选的信息系统开发编程语言,然而我们必须注意到,Java 8已经面临支持结束的阶段。在这个时间节点上,我们应认真考虑Java 17升级计划,做好必要的调研与对策。 

基础开源软件的维护周期大约是5-10年

持续迭代更新,是开源软件能保持生命力的重要原因。

如果我们考察几个与Java密切相关的开源软件,就会发现它们设置的长期支持计划(long term support,LTS)大约在5年左右。

1. Linux,6年 

可以从Linux内核的开发时间表上看出每个LTS版本维护期大约是6年。

2. Spring Framework,5年

Spring Framework是Java企业应用开发常用框架之一,从2.x版本(2006年)开始就保持一个相对固定的迭代周期,每个大版本保持约5年的更新维护期。

3. Spring Boot,5年 

Spring Boot保持了和Spring Framework相似的更替周期。

1.0 正式发布于2014年,1.x最后一个版本1.5.x发布于2018年,免费支持到2021年。

2.0 发布于2018年,当前版本是2.7,免费支持到2024年。3.0发布于2022,最低要求是Java17。

2.x 距今已经有4年,估计2.7可能是最后一个版本,但应该会延长支持(安全修复)以方便过渡到3.x。

 

Java8之后Oracle调整了发版规则与授权协议

再详细讲一下Java的情况,Java8以及之前的版本,保持平均2年一个小升级的节奏(Java 1.0 1996年——1.8 2014年),兼容与稳定带来Java平台的繁荣发展。

2009年Oracle收购Sun公司,Java转移到Oracle名下。2020年时,Oracle变更Java授权协议,开始区分免费与商用。 

简单讲 Oracle JDK8 2020年(Oracle_JDK_180_202)的版本可以自由使用,2020以后的版本若用于商业用途需要付费,最终支持到2030年。

另外,从Java9开始,更新节奏加快。OpenJDK会保持6个月一个版本的节奏,大约每隔3年会发布一个长期支持版版的Open JDK(这意味着8之后稳定版是11、17)。Oracle也会相应的发布LTS的Oracle JDK,一个版本维护约5年,超期要购买付费支持。

Java版本升级之所以加快,也是受到新兴技术、新编程语言的影响,担心Java技术栈落后于人。

必须再提一下OpenJDK,这是Java平台(J2SE)的参考实现,也是开源(GPL)且自由使用的JDK。Oracle JDK也是在OpenJDK基础上添加专有组件和商业支持后的版本。目前业界普遍倾向优先使用OpenJDK来避免Oracle JDK License的限制。

Java17升级路线 

为了让读者们快速、清晰地了解如何顺利地升级到Java17,笔者整理出以下4个步骤:

第一步:解决OpenJDK8 Runtime的兼容性问题 

首先,应当解决OpenJDK8的兼容性问题。

建立OpenJDK8的运行环境,在其中启动程序来识别兼容性问题。

相对来说,从Oracle JDK迁移到OpenJDK应该是完全兼容的,但现实中往往打脸。首先保持与OpenJDK 8的无缝切换可以为后续升级打下基础。你可能会遇到的问题及解决办法:

01、存在对Oracle JDK的特殊条件判断

可通过调整代码解决,不应该再对JDK的供应商做判断了 

02、对专有package 的引用

例如:com.sun.*, sun.misc.*,可替换成相同功能的开源组件或者使用Java提供的正式接口 

03、缺少个别library(例如javafx,javax*)

可通过引入依赖项解决,这些依赖原本就不是JDK的一部分 

完成这一步,可以让程序摆脱 Oracle JDK 的专有依赖,是后续工作的基础。 

第二步:解决Java17 Runtime 兼容性问题 

建立 Java17 的运行环境,在新环境中尝试启动程序识别运行时兼容性问题,这一步不会改变程序的编译设置。

得益于Java的兼容性设计,旧版Java代码理论上可以无差错地在新版环境中运行。即便遇到问题,也是相对容易解决的。你可能会遇到的问题及解决方法:

01、JVM启动参数不再支持

此时应当更换新启动参数

02、硬编码的Java版本判断导致启动异常

 在源代码中补充完善判断条件

03、字节码处理模块异常

例如:asm、cglib、lombok,一般将类库升级到更高的兼容版即可。对于使用了依赖管理的程序,这一步容易操作,如果你的程序还在使用直接jar依赖构建,你应该先考虑迁移到使用Maven管理依赖。

完成这一步,程序既不用改变开发环境,又有了对高版本运行环境的兼容性。即便你不打算立即使用Java17新功能进行开发,这么做也是值得的。 

第三步:解决Compile Time 兼容性问题 

此时,升级开发环境到 JDK17 ,但编译目标仍然保持为8,开始解决编译问题。这一步也是最为困难的。 可能出现的问题及解决办法:

01、类找不到

 这种情况在之前的步骤中已经排除大半,继续识别依赖升级即可。

02、编译错误

依赖注解处理、字节码生成、代码生成工具的编译辅助工具可能会报错,需要升级这些工具的版本。

03、测试套件(Junit)报错

自动化测试的错误需要逐个处理。也可能是是框架在反射调用上有变化,统一处理一次就好。

04、编译通过了但启动异常

大概率在异常处理,判断逻辑上有过时用法,与第二个阶段中提到的处理方式一样。 

05、组件还没有支持17的版本

这时可先升级到 JDK11 来过渡,如果组件连没有兼容JDK11的版本都没有,那可能要考虑更换这个组件或暂缓第三步工作。 

可能还会遇到其他问题,这个也是大家最为担心而不愿意主动升级的原因。这时候平常积累的自动化测试套件、全量的回归案例、性能测试套件就应该派上用场了。执行这些测试套件来验证软件仍在按期望工作。

第四步:完全升级到 Java17

在成功完成前面三个步骤之后,第四步是更改 compile target 为17,使用语法的新功能。

此处摘录新功能中较为重要的一些供参考:

JDK11:

  • 对TLS1.3加密的支持,JEP 332: Transport Layer Security (TLS) 1.3  

  • 用var关键词声明局部变量,JEP 323: Local-Variable Syntax for Lambda Parameters

  • JEP 327: Unicode 10

  • 新GC算法,JEP 333: ZGC: A Scalable Low-Latency Garbage Collector

 JDK14:

  • 精确提醒空指针异常位置, JEP 358: Helpful NullPointerExceptions

  • Switch 可使用表达式,JEP 361: Switch Expressions

 JDK15:

用三引号写多行字符串不必再转义:JEP 378: Text Blocks

 JDK16:

  • 减少JDK体积方便容器构建:JEP 386: Alpine Linux Port

  • JEP 387: Elastic Metaspace JDK

  • 新类型record(与class、enum并列):JEP 395: Records

JDK17:

封口类:JEP 409: Sealed Classes 

小结 

本文提供了一个稳妥的分步骤实施策略,一至四步你可以在任一步骤后安全暂停,而无需全部一次性完成。

实际实施时,还可以根据程序修改的活跃程度以及使用的技术栈的新旧程度来制定不同目标的计划:

 总之,保持基础框架合适的升级换代周期是一个明智的决策。

停止支持的软件就像长期无人居住的房屋一样,最终将面临缺陷修复困难、安全漏洞逐年增加、不支持新的安全算法和协议等问题。

猜你喜欢

转载自blog.csdn.net/summer_fish/article/details/129944886