从 Java 8 升级到 Java 17 需要注意哪些兼容性问题?
从 Java 8 升级到 Java 17 需依次确认 JDK 与构建工具版本、将编译目标设为 17、补回 JAXB 等移除的 Java EE 模块、处理 sun.misc 等内部 API 强封装,并在 Spring Boot 3 中把 ja
学完这篇你能得到一份从 Java 8 升到 Java 17 的兼容性检查清单,知道先改哪个配置、哪些 API 已经没了、哪些启动参数会让 JVM 直接拒绝启动。
第一步:确认现有版本和构建链
这一步要摸清你当前用的 JDK、Maven、Gradle 和 IDE 版本,避免升级到一半发现构建工具本身不支持 Java 17。在项目根目录执行:
java -version
mvn -version
./mvnw -version
如果输出里是 1.8.0_xxx,说明还在 Java 8。Maven 建议 3.8.6 以上,Gradle 建议 7.3 以上,IntelliJ IDEA 建议 2021.3 以上。IDEA 里改 SDK 的入口是:File → Project Structure → Project → Project SDK 选 17,Language level 选 17;Maven 导入 JDK 在 Settings → Build, Execution, Deployment → Build Tools → Maven → Importing → JDK for importer 选 17。
注意:只改 IDEA 的 SDK 不够,Maven 或 Gradle 的编译插件没改,
mvn clean test仍然按旧版本编译。
第二步:把编译目标改成 17
这一步要让编译器和构建工具都按 Java 17 的 API 和字节码检查,做完后本地能编译通过。Maven 项目在 pom.xml 里加:
<properties>
<maven.compiler.release>17</maven.compiler.release>
</properties>
Gradle 项目在 build.gradle 里写:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
注意:用
--release 17或maven.compiler.release,不要只写source和target。只写 source/target 时,编译器仍可能让你调用当前 JDK 才有的 API,放到 Java 17 运行环境会NoSuchMethodError。
第三步:处理被移除的 Java EE 模块
这一步要补回 Java 11 起从 JDK 中移除的 JAXB、JAX-WS、JTA、CORBA 和 javax.annotation,否则启动时会报 ClassNotFoundException。常见报错是 javax.xml.bind.JAXBException、javax.annotation.Resource、javax.activation.DataSource。Maven 里加:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.3</version>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
如果你用 Spring Boot 3.x,包名要从 javax.* 换成 jakarta.*,这是 Jakarta EE 9 的命名空间迁移,不是改依赖版本就能绕过去的。
第四步:处理 JDK 内部 API 强封装
这一步要找出代码里对 sun.misc.*、sun.reflect.*、java.base 非导出包的反射调用,否则 Java 16 以后默认拒绝访问。用 JDK 自带的 jdeps 扫描:
jdeps --jdk-internals -R target/your-app.jar
jdeprscan --release 17 target/classes
如果输出里有 sun.misc.Unsafe、java.lang.reflect 访问 java.base/java.lang 之类的记录,优先改代码;实在改不了,启动参数加:
--add-opens java.base/java.lang=ALL-UNNAMED
--add-exports java.base/sun.nio.ch=ALL-UNNAMED
注意:
--illegal-access=permit在 Java 17 已经无效,别指望靠它放行。
第五步:删掉已移除的 API 和 GC 参数
这一步要清理 Java 17 中已经删除或默认不可用的东西,否则 JVM 启动直接失败。重点检查:Nashorn 引擎(Java 15 移除)、CMS GC(Java 14 移除)、Pack200(Java 14 移除)、Applet API、RMI Activation、SecurityManager(Java 17 标记为待移除)。旧 GC 日志参数 -XX:+PrintGCDetails、-XX:+PrintGCTimeStamps 要换成:
-Xlog:gc*:file=gc.log:time,uptime,level,tags
注意:Java 9 以后默认 GC 是 G1,如果原来依赖 CMS 的低停顿表现,先在测试环境用
-XX:+UseG1GC跑压测,不要直接上生产。
第六步:升级框架和依赖版本
这一步要把 Spring、Lombok、Mockito、字节码库升到支持 Java 17 的版本,做完后编译和测试才能稳定跑。Spring Boot 2.7.x 可以跑在 Java 17 上;Spring Boot 3.x 要求 Java 17+,同时把 javax.* 换成 jakarta.*。Lombok 用 1.18.20 以上,Mockito 用 4.x 以上,Byte Buddy 用 1.11.x 以上,ASM 用 9.x 以上,Log4j 2 用 2.17 以上。
注意:老版本 CGLIB 和 ASM 在 Java 17 上可能报
Unsupported class file major version 61,优先升依赖,而不是加--add-opens硬扛。
第七步:跑测试和运行时验证
这一步要用完整测试和启动验证确认兼容性,做完后你才知道还有没有漏网之鱼。执行:
mvn clean test
mvn clean package
java -jar target/your-app.jar
重点看异常栈里有没有 InaccessibleObjectException、NoClassDefFoundError、UnsupportedClassVersionError,以及 GC 日志是否正常输出。
注意:
_作为单个下划线标识符在 Java 9 是警告,Java 17 是编译错误;旧代码里如果有int _ = 1;必须改名。
小结
- 先改构建工具和 IDE 的 JDK 到 17,再用
maven.compiler.release=17统一编译目标。 - Java 11 起移除 Java EE 模块,JAXB、JAX-WS、JTA、
javax.annotation要手动加依赖。 - Java 16 起强封装 JDK 内部 API,用
jdeps --jdk-internals扫描,必要时加--add-opens。 - CMS、Nashorn、Pack200、旧 GC 日志参数在 Java 17 不可用,启动参数要同步替换。
- Spring Boot 3.x 必须 Java 17+,并且
javax.*要迁移到jakarta.*。 - 升级后必须跑完整测试和实际启动,重点排查
InaccessibleObjectException和NoClassDefFoundError。
原文链接:https://www.gj0.com/thread-1712.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。