⭐ 推荐:社区规则条款 V1.0

从 Java 8 升级到 Java 17 需要注意哪些兼容性问题?

chinaz
chinaz 初级会员超兽战士
发布于 2026-10-12 10:28 ·2 浏览 ·0 回复
内容摘要

从 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。
版权声明:本文来自 GJ站长论坛《从 Java 8 升级到 Java 17 需要注意哪些兼容性问题?》
原文链接:https://www.gj0.com/thread-1712.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。

全部回复 0

还没有回复,来抢沙发~