当前位置: 首页 > news >正文

JDK从8升级到21的问题集

一、背景与挑战

1.升级动因
Oracle长期支持策略
现代特性需求:协程、模式匹配、ZGC等
安全性与性能的需求
AI新技术引入的版本要求
2.项目情况
100+项目并行升级的协同作战
多技术栈并存
持续集成体系的适配挑战

 

二、进度

应用总数 已完成 应用下线 待升级
100+ 73 13 10+

 

三、主要问题域与解决方案

1. 依赖管理的"蝴蝶效应"

sun.misc.BASE64Encoder等内部API废弃 → 引发编译错误
JAXB/JAX-WS从JDK核心剥离 → XML处理链断裂
Lombok与新版编译器兼容性问题(尤其record类型)

核心原因在于JEP320提案:https://openjdk.org/jeps/320

 

案例1:历史SDK的编译陷阱

Compilation failure: Compilation failure:
#14 4.173 [ERROR] 不再支持源选项 6。请使用 8 或更高版本。
#14 4.173 [ERROR] 不再支持目标选项 6。请使用 8 或更高版本。
<!-- 旧版本编译器配置导致构建失败 -->
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.5</version><configuration><source>1.6</source><target>1.6</target></configuration>
</plugin>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.13.0</version><configuration><release>8</release><!-- 统一使用release参数 --></configuration>
</plugin>

运行 HTML

案例2:JAXB的模块化剥离

javax.xml.bind.JAXBException:Implementation of JAXB-API has not been found
<dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId><version>4.0.5</version>
</dependency>

案例3:Lombok与新版编译器兼容性问题

java: java.lang.NoSuchFieldError
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version>
</dependency>

案例4:Resource注解找不到

Caused by: java.lang.NoSuchMethodError: 'java.lang.String javax.annotation.Resource.lookup()'
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.<init>(CommonAnnotationBeanPostProcessor.java:664)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.lambda$buildResourceMetadata$0(CommonAnnotationBeanPostProcessor.java:395)
at org.springframework.util.ReflectionUtils.doWithLocalFields(ReflectionUtils.java:669)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.buildResourceMetadata(CommonAnnotationBeanPostProcessor.java:377)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.findResourceMetadata(CommonAnnotationBeanPostProcessor.java:358)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(CommonAnnotationBeanPostProcessor.java:306)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:1116)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
... 37 more
<dependency><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>1.3.5</version>
</dependency><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version>
</dependency>

上述两个依赖代码基本一样,推荐使用该版本:

jakarta.annotation:jakarta.annotation-api。

 

2. 模块化的破与立

反射访问的模块墙

[ERROR] Unable to make field private int java.text.SimpleDateFormat.serialVersionOnStream accessible
# 启动参数添加模块开放配置
--add-opens java.base/java.text=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED

完整模块开放配置模板

export JAVA_OPTS="-Djava.library.path=/usr/local/lib -server -Xmx4096m --add-opens java.base/sun.security.action=ALL-UNNAMED
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/sun.util.calendar=ALL-UNNAMED
--add-opens java.base/java.util.concurrent=ALL-UNNAMED
--add-opens java.base/java.util.concurrent.locks=ALL-UNNAMED
--add-opens java.base/java.security=ALL-UNNAMED
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.base/sun.nio.ch=ALL-UNNAMED
--add-opens java.management/java.lang.management=ALL-UNNAMED
--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED
--add-opens java.management/sun.management=ALL-UNNAMED
--add-opens java.base/sun.security.action=ALL-UNNAMED
--add-opens java.base/sun.net.util=ALL-UNNAMED
--add-opens java.base/java.time=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED"

3. 语法层面的"时空穿越"

案例1:Base64编解码改造

// JDK8写法(已废弃)
BASE64Encoder encoder =newBASE64Encoder();
String encoded = encoder.encode(data);
// JDK21规范写法
Base64.Encoder encoder =Base64.getEncoder();
String encoded = encoder.encodeToString(data);

案例2:日期序列化问题

Caused by:java.lang.reflect.InaccessibleObjectException: 
Unable to make field private int java.text.SimpleDateFormat.serialVersionOnStream accessible

解决方案

1.使用DateTimeFormatter替代SimpleDateFormat
2.或添加模块开放参数:--add-opens java.base/java.text=ALL-UNNAMED

 

4. 隐秘的"依赖战争"

注解包冲突典型案例

[ERROR] javax.annotation.Resource exists in both 
jsr250-api-1.0.jar and jakarta.annotation-api-1.3.5.jar
<!-- 统一使用Jakarta标准 -->
<dependency><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>2.1.1</version>
</dependency>
<!-- 排除旧版本依赖 -->
<exclusions><exclusion><groupId>javax.annotation</groupId><artifactId>jsr250-api</artifactId></exclusion>
</exclusions>

5. 构建体系的改造

Maven插件兼容性问题

[ERROR] The plugin org.apache.maven.plugins:maven-compiler-plugin:3.13.0 
requires Maven version 3.6.3

升级策略

1.升级Maven版本
2.统一插件版本
<build><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.13.0</version></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>3.4.0</version></plugin></plugins></pluginManagement>
</build>

四、最佳实践总结

1. 本地编译

第一步:在本地进行编译,提前识别出语法错误、版本冲突及不兼容问题。

主要有以下几种场景:

Base64:参照 【Base64编解码改造】

lombok:升级版本

jsr250、jaxb-runtime、jakarta.annotation-api:参照 【注解包冲突典型案例】

maven-compiler-plugin:升级版本

maven-resources-plugin:升级版本

maven-war-plugin:升级版本

 

 

2. 行云构建

同【本地编译】

 

3. 行云部署

a、镜像不匹配:自定义镜像或者使用已申请的jdk21镜像

b、module权限不够:参照【完整模块开放配置模板

c、JDSecurity加解密

所有数据库操作:important.properties配置文件的处理方式

classpath:important.properties 使用PropertyPlaceholderConfigurer进行处理,不要用JDSecurityPropertyFactoryBean。

<!--    <bean id ="secApplicationProperties" class="com.jd.security.configsec.spring.config.JDSecurityPropertyFactoryBean">-->
<!--       <property name="ignoreResourceNotFound" value="true" />-->
<!--       <property name="secLocation" value="classpath:important.properties"/>-->
<!--    </bean>-->

 

4. 运行

a、序列化异常

jdk21使用列表视图作为入参,导致jsf接口进行反序列化报错。报错代码如下:

List<String> subList = venderCodes.subList(i * batchSize, Math.min(venderCodes.size(), (i + 1) * batchSize));
VendorQueryVo vendorQueryVo = new VendorQueryVo();
vendorQueryVo.setVendorCodes(subList);
// 该接口最多支持100条调用
List<VendorVo> batchVendorNameByVendorCode = vendorBaseInfoService.getBatchVendorNameByVendorCode(vendorQueryVo, I18NParamFactory.getJDI18nParam());

将 vendorQueryVo.setVendorCodes(subList) 修改为vendorQueryVo.setVendorCodes(new ArrayList<>(subList)) 即可解决问题

 

b、线程上下文类找不到:使用多线程场景下尽可能使用显式指定线程池【默认情况下 不同运行环境的处理机制不同】

 

 

5. JVM调优

垃圾回收调优

UseParallelGCUseG1GCUseZGC是 Java 虚拟机(JVM)中三种不同的垃圾回收器(Garbage Collector, GC),它们的设计目标和使用场景有所不同。以下是它们的区别:

特性 UseParallelGC UseG1GC UseZGC
设计目标 高吞吐量 平衡吞吐量和延迟 极低延迟
暂停时间 较长 较短 极短
适用堆大小 中小堆(几 GB 到几十 GB) 大堆(几十 GB 到几百 GB) 超大堆(TB 级别)
CPU 消耗 中等 中等 较高
适用场景 批处理、计算密集型任务 对延迟有一定要求的应用 对延迟极其敏感的应用
如果你的应用对吞吐量要求高,且可以接受较长的暂停时间,选择UseParallelGC
如果你的应用对延迟有一定要求,且堆内存较大,选择UseG1GC
如果你的应用对延迟极其敏感,且堆内存非常大,选择UseZGC

仅供参考,具体请按照实际情况来进行调整。

6. RSS内存异常

RSS内存有问题的应用可以尝试使用jemalloc方式替换linux默认的glibc内存分配方式。

问题现象:启动后RSS内存使用率很快达到90%以上,甚至接近于100%。

使用方式:启动脚本增加

if [ ! -f "/usr/local/lib/libjemalloc.so.2" ]; then sudo wget -O /usr/local/lib/libjemalloc.so.2 http://storage.jd.local/ste/jemalloc/x86/5.3.0/libjemalloc.so.2 fi export LD_PRELOAD=$LD_PRELOAD:/usr/local/lib/libjemalloc.so.2

使用效果:

 


 

 

默认模式下稳定后的RSS内存在80%左右,替换后稳定在50%左右,且容器内存使用率也有所变化。

https://taishan.jd.com/mdc/ipMonitor?ip=11.31.93.15&startTime=1747238400000&endTime=1747361529820

http://www.hskmm.com/?act=detail&tid=13461

相关文章:

  • 超前探展!2025 云栖大会朋友圈晒图必备
  • 进程池
  • AutoCAD 2025 CAD 安装包中文永久免费免激活破解版下载及详细安装教程
  • 报表神器Stimulsoft再升级!Stimulsoft Reports、Dashboards 和 PDF Forms 2025.4 即将发布!
  • 题解:AT_agc027_e [AGC027E] ABBreviate
  • 【PostgreSQL 17】11 窗口函数
  • 商家列表管理与公众号二维码绑定​,方便对用户进行消息通知提醒
  • linux权限细化管理的三种方法:polkit sudoer doas做权限管理
  • mysql常用
  • 国产化Excel开发组件Spire.XLS教程:Python 写入 Excel 文件,数据写入自动化实用指南
  • Ansible的安装和使用
  • 数显LED驱动芯片恒流数码管驱动IC内置显示RAM为816位 VK16D33
  • 详细介绍:【TEC045-KIT】基于复旦微 FMQL45T900 的全国产化 ARM 开发套件
  • 【IEEE出版】2025年智慧物联与电子信息工程国际学术会议(IoTEIE 2025)
  • 9.22 机房练习
  • eslint
  • 视频调色神器!CyberLink ColorDirector:从入门到专业的视频色彩魔法工具
  • Leveraging Context-Aware Prompting for Commit Message Generation 论文笔记
  • P4951 [USACO01OPEN] Earthquake 题解
  • 用ida插件快速审计函数调用
  • 【ACM独立出版|往届已EI、Scopus检索|合作SSCI】第二届数字经济与计算机科学国际学术会议(DECS 2025)
  • schematool -initSchema -dbType mysql
  • PostgreSQL 全表 count 优化实践:从 SeqScan 痛点分析到 heapam 改进与性能突破
  • 第二章习题
  • Lightroom Classic 2025:精细调控,呈现完美画质,专业级数字照片管理与后期处理全解析
  • langfuse从v2.70.1升级到V3.110(异机升级+数据迁移)
  • 20250518_信安一把梭_医院抓取流量
  • tsx 图论选讲
  • OTP绕过漏洞:当后端过度信任前端时的安全灾难
  • 2MHz 8-bit 微控制器 with 64 Pins,M38049FFLKP ADR5040ARTZ TMS320F28062PZT K4AAG165WA-BCTD存储器