百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

JDK从8升级到21的问题集(jdk1.6升级到1.8要考虑的因素)

lipiwang 2025-06-09 23:26 2 浏览 0 评论

一、背景与挑战

1.升级动因

oOracle长期支持策略

o现代特性需求:协程、模式匹配、ZGC等

o安全性与性能的需求

oAI新技术引入的版本要求

2.项目情况

o100+项目并行升级的协同作战

o多技术栈并存

o持续集成体系的适配挑战


二、进度

应用总数

已完成

应用下线

待升级

100+

73

13

10+


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

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

osun.misc.BASE64Encoder等内部API废弃 → 引发编译错误

oJAXB/JAX-WS从JDK核心剥离 → XML处理链断裂

oLombok与新版编译器兼容性问题(尤其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调优

垃圾回收调优

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

特性

UseParallelGC

UseG1GC

UseZGC

设计目标

高吞吐量

平衡吞吐量和延迟

极低延迟

暂停时间

较长

较短

极短

适用堆大小

中小堆(几 GB 到几十 GB)

大堆(几十 GB 到几百 GB)

超大堆(TB 级别)

CPU 消耗

中等

中等

较高

适用场景

批处理、计算密集型任务

对延迟有一定要求的应用

对延迟极其敏感的应用

o如果你的应用对吞吐量要求高,且可以接受较长的暂停时间,选择UseParallelGC

o如果你的应用对延迟有一定要求,且堆内存较大,选择UseG1GC

o如果你的应用对延迟极其敏感,且堆内存非常大,选择UseZGC

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

相关推荐

Java 实体映射工具 MapStruct(jpa实体类映射类)

简介:让你的DO(业务实体对象),DTO(数据传输对象)数据转换更简单强大前言在软件架构中,分层式结构是最常见,各层之间有其独立且隔离的业务逻辑,也因而各层有自己的输入输出对象,也就是代码中见到各...

@Date不管用怎么办,想少写get和setter方法,怎么办

学习交流群:293911833,有遇到问题的,可以加一下群,大家互相交流,一起进步今天在使用lombok的时候,为什么@Date不管用,是我映射没做好吗?还是其他的,后来查了一些大佬的资料终于找到问...

Spring系列之集成MongoDB的2种方法

MongoDB是最流行的NoSQL数据库,SpringBoot是使用Spring的最佳实践。今天带大家讲一讲SpringBoot集成MongoDB的两种方式,MongoDB的安装自行去官网查询,本地开...

Spring Boot集成SLF4j详解(springboot集成knife4j)

SpringBoot集成SLF4j详解:从基础到高级实践SLF4j(SimpleLoggingFacadeforJava)是一个日志门面框架,提供统一的日志接口,允许开发者灵活切换底层...

自定义代码生成器(上)(代码自动生成器)

1概述1.1介绍在项目开发过程中,有很多业务模块的代码是具有一定规律性的,例如controller控制器、service接口、service实现类、mapper接口、model实体类等等,这部分代...

Java系统开发从入门到精通第四讲(文字版)

课程目标:了解重要的JavaAPI和一些必备框架的使用,这些都是系统开发的标配需要掌握日期时间APIJava8通过发布新的Date-TimeAPI(JSR310)来进一步加强对日期与时间...

重拾JAVA:这种编程语言为什么不行了?

全文共2322字,预计学习时长6分钟为了应对新工作,笔者在过去两周一直在重新熟悉一位老朋友:JAVA。我以JAVA开启了我的软件事业,与之共行了两年半左右的时间。但是随着容器和微服务的出现,JAVA很...

一款提高Java开发效率的工具(java怎么提高技术)

今天来介绍一款Java常用插件:Lombokhttps://projectlombok.org/通常在用Java代码开发项目过程中,都会建立各种各种的Bean类,如下:publicclassSea...

JDK从8升级到21的问题集(jdk1.6升级到1.8要考虑的因素)

一、背景与挑战1.升级动因oOracle长期支持策略o现代特性需求:协程、模式匹配、ZGC等o安全性与性能的需求oAI新技术引入的版本要求2.项目情况o100+项目并行升级的协同作战o多技术栈并存o持...

Lombok:让Java代码变得优雅简洁的秘密武器

Lombok:让Java代码变得优雅简洁的秘密武器在Java的世界里,代码量往往是一个开发者幸福感的重要衡量指标。代码写得越少,出错的可能性就越小,同时维护起来也更轻松。而Lombok正是这样一个让J...

SpringToolSuite(STS)安装lombok插件

一、打开maven仓库,找到lombok所在的文件夹二、在命令行中运行java-jarlombok-1.18.20.jar,打开lombok插件安装的可视化界面。三、选择STS安装目录,点击Ins...

年末将至,Java 开发者必须了解的 15 个Java 顶级开源项目

专注于Java领域优质技术,欢迎关注作者:SnailClimbStar的数量统计于2019-12-29。1.JavaGuideGuide哥大三开始维护的,目前算是纯Java类型项目中Sta...

相见恨晚,一个架构师也不会用的Lombok注解

原创:不羡鸳鸯不羡仙,一行代码调半天。小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。我见过很多反对Lombok的同学,背地里又偷偷的把插件添加了进去,这是真香原理在搞鬼。嘴上说...

第二弹!安排!安利几个让你爽到爆的IDEA必备插件

作者:Guide哥来自:JavaGuide大家好,我是Guide哥。上一篇关于IDEA插件推荐的文章:《第一弹!安排!安利10个让你爽到爆的IDEA必备插件!》收到了很多小伙伴的好评,时隔大半个月...

Java @Data注解(java @order注解)

1、@Data注解是lombok.jar包下的注解,该注解通常用在实体bean上,不需要写出set和get方法,但是具备实体bean所具备的方法,简化编程提高变成速度。2、@Data相当于@Gette...

取消回复欢迎 发表评论: