必须检查项目实际使用的JDK版本是否与终端显示一致,重点确认编译器(javac)、运行时(java)、构建配置(如Maven的maven-compiler-plugin)及部署环境(如Docker镜像)四者对齐;若javac为21而java仍为17,说明运行时未切换;Maven需确保、和均设为21;Gradle需同步更新sourceCompatibility和targetCompatibility;还需验证Spring Boot、Log4j等第三方库是否兼容JDK 21,避免UnsupportedClassVersionError或InaccessibleObjectException等运行时异常。

先检查项目实际使用的 JDK 版本,而不是终端里 java -version 显示的那个。
很多人升级失败,是因为只改了 shell 的默认 JDK,但构建工具、IDE 或容器里用的还是旧版本。必须确认四点是否对齐:编译器(javac)、运行时(java)、构建配置(如 Maven 的 maven-compiler-plugin)、以及部署环境(如 Docker 镜像或 Jenkins 容器里的 JDK)。
检查 javac 和 java 是否版本一致
在终端执行:
javac -version<br>java -version
两者输出的主版本号必须都是 21。如果 javac 是 21 而 java 还是 17,说明运行时没切过去——常见于 CI/CD 脚本硬编码了 /usr/lib/jvm/java-17-openjdk-amd64/bin/java 这类绝对路径。
检查构建工具是否锁定旧版本
Maven 项目重点看 pom.xml 中的 maven-compiler-plugin 配置:
-
<source></source>和<target></target>必须设为21 - 更关键的是
<release></release>:如果它存在且值为17,那即使你装了 JDK 21,编译出的字节码仍是 Java 17 兼容格式,UnsupportedClassVersionError不会立刻暴露,但新 API(如SequencedCollection)无法使用 - Gradle 用户检查
sourceCompatibility和targetCompatibility是否同步更新
检查第三方库是否支持 JDK 21
Spring Boot 2.x、Log4j 1.x、Hibernate 5.x、旧版 Lombok()等大概率不兼容。典型症状包括:
-
NoClassDefFoundError: javax/xml/bind/JAXBContext(JDK 11+ 已移除javax.*,需迁移到jakarta.*) -
InaccessibleObjectException(反射访问被强封装的内部类,比如 Spring 早期版本调用sun.misc.Unsafe) - 运行时抛出
IllegalAccessError或LinkageError,尤其在使用字节码增强框架(ByteBuddy、CGLIB)时
验证方式:jdeps --jdk-internals your-app.jar 可快速扫描是否依赖已移除的内部 API;查 Maven Central 上对应库的 Compatibility 标签或 Release Notes,确认明确支持 JDK 21。
最容易被忽略的是:JDK 21 默认启用更强的模块封装,很多老项目靠 --add-opens 参数临时绕过,但这只是补丁,不是解法。真正的升级必须同步更新依赖版本,否则上线后某个深夜的 Full GC 或并发高峰就可能触发隐藏异常。


















