20、JDK 17 新特性:JDK 17 迁移指南:从 JDK 8/11 升级的注意事项

从 JDK 8 或 JDK 11 升级到 JDK 17,鹏磊最烦的就是各种兼容性问题。代码编译不过,运行时出错,第三方库不兼容,一堆问题。这篇文章就给你整一个完整的迁移指南,帮你把应用从 JDK 8/11 平滑升级到 JDK 17。

从 JDK 8/11 升级到 JDK 17 是个大工程,需要检查代码兼容性、更新第三方库、调整配置参数。这玩意儿虽然工作量不小,但 JDK 17 是 LTS 版本,性能和安全都有提升,值得升级。建议制定详细的迁移计划,逐步执行,充分测试,确保平滑升级。

迁移前准备

迁移前需要做好准备工作:

检查当前环境

检查当前 JDK 版本和依赖:

# 检查当前 JDK 版本
java -version

# 检查编译版本
javac -version

# 检查项目依赖
mvn dependency:tree
# 或
gradle dependencies

检查当前环境能帮你了解迁移的起点。

使用 jdeps 检查依赖

使用 jdeps 工具检查 JDK 内部 API 依赖:

# 检查 JDK 内部 API 依赖
jdeps --jdk-internals MyApp.jar

# 检查模块依赖
jdeps --list-deps MyApp.jar

# 生成依赖报告
jdeps -dotoutput deps MyApp.jar

使用 jdeps 工具能帮你找出所有依赖内部 API 的地方。

使用 jdeprscan 检查废弃 API

使用 jdeprscan 工具检查废弃 API:

# 检查废弃 API
jdeprscan MyApp.jar

# 检查特定版本
jdeprscan --release 17 MyApp.jar

使用 jdeprscan 工具能帮你找出所有使用废弃 API 的地方。

从 JDK 8 升级

从 JDK 8 升级到 JDK 17,需要注意:

模块系统

JDK 9 引入了模块系统,JDK 17 继续使用:

// JDK 8:不需要模块声明
// 可以直接使用所有类

// JDK 17:可能需要模块声明
module my.module {
    requires java.base;
    requires java.desktop;
    exports com.example;
}

如果项目没有模块化,可以继续使用类路径,但建议逐步模块化。

内部 API 封装

JDK 17 强封装了内部 API:

// JDK 8:可以访问内部 API
// import sun.misc.Unsafe;  // 可以访问

// JDK 17:无法访问内部 API
// import sun.misc.Unsafe;  // 无法访问
// 需要使用公开 API 替代

需要将内部 API 迁移到公开 API。

废弃 API

JDK 8 到 JDK 17 之间废弃了很多 API:

// JDK 8:使用某些 API
// JDK 17:这些 API 可能被废弃或移除
// 需要使用替代方案

需要检查并更新废弃的 API。

从 JDK 11 升级

从 JDK 11 升级到 JDK 17,相对简单一些:

--illegal-access 选项移除

--illegal-access 选项在 JDK 17 中被移除:

# JDK 11:可以使用 --illegal-access
java --illegal-access=permit MyApp

# JDK 17:--illegal-access 被移除
java --illegal-access=permit MyApp  # 错误:未知选项

需要移除 --illegal-access 选项,使用公开 API。

内部 API 完全封装

JDK 17 完全封装了内部 API:

// JDK 11:可能还能访问某些内部 API(有警告)
// JDK 17:完全无法访问
// 需要使用公开 API 替代

需要将内部 API 迁移到公开 API。

迁移步骤

步骤一:更新构建工具

更新构建工具到支持 JDK 17 的版本:

<!-- Maven 配置 -->
<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
// Gradle 配置
java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

更新构建工具确保能正确编译。

步骤二:更新第三方库

更新第三方库到支持 JDK 17 的版本:

<!-- 检查库是否支持 JDK 17 -->
<!-- 更新到最新版本 -->
<dependencies>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>my-library</artifactId>
        <version>2.0.0</version>  <!-- 更新版本 -->
    </dependency>
</dependencies>

更新第三方库确保兼容性。

步骤三:修复编译错误

修复编译错误:

// 错误:使用内部 API
// import sun.misc.Unsafe;

// 正确:使用公开 API
import jdk.incubator.foreign.*;

// 错误:使用废弃 API
// String s = new String(bytes, "ISO-8859-1");

// 正确:使用新 API
String s = new String(bytes, StandardCharsets.ISO_8859_1);

修复编译错误确保代码能编译通过。

步骤四:运行测试

运行所有测试确保功能正常:

# 运行单元测试
mvn test

# 运行集成测试
mvn verify

# 运行所有测试
gradle test

运行测试确保功能正常。

步骤五:性能测试

进行性能测试确保性能不下降:

// 性能测试
// 1. 对比升级前后的性能
// 2. 检查 GC 性能
// 3. 检查内存使用
// 4. 检查 CPU 使用

性能测试确保性能不下降。

常见问题

问题一:内部 API 访问失败

内部 API 访问失败是最常见的问题:

// 问题:访问内部 API 失败
// import sun.misc.Unsafe;  // 无法导入

// 解决方案:使用公开 API
import jdk.incubator.foreign.*;

// 使用外部函数和内存 API 替代 Unsafe
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
    MemorySegment segment = MemorySegment.allocateNative(100, scope);
    // 使用内存段
}

使用公开 API 替代内部 API。

问题二:第三方库不兼容

第三方库可能不兼容 JDK 17:

# 问题:第三方库不兼容
# 解决方案:
# 1. 更新库到最新版本
# 2. 寻找替代方案
# 3. 联系库维护者

更新库或寻找替代方案。

问题三:废弃 API 警告

废弃 API 可能产生警告:

// 问题:使用废弃 API
// @Deprecated
// public void oldMethod() {}

// 解决方案:使用新 API
public void newMethod() {
    // 新实现
}

使用新 API 替代废弃 API。

实际迁移案例

案例一:Spring Boot 应用迁移

Spring Boot 应用迁移示例:

<!-- Spring Boot 配置 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.0</version>  <!-- 支持 JDK 17 -->
</parent>

<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

Spring Boot 3.0+ 支持 JDK 17,迁移相对简单。

案例二:Maven 项目迁移

Maven 项目迁移示例:

<!-- Maven 配置 -->
<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>17</source>
                <target>17</target>
            </configuration>
        </plugin>
    </plugins>
</build>

更新 Maven 配置支持 JDK 17。

案例三:Gradle 项目迁移

Gradle 项目迁移示例:

// Gradle 配置
plugins {
    id 'java'
}

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

compileJava {
    options.release = 17
}

更新 Gradle 配置支持 JDK 17。

迁移检查清单

迁移检查清单能帮你系统化地迁移:

// 迁移检查清单
// 1. 检查 JDK 版本
//    - 确认当前版本
//    - 确认目标版本
//
// 2. 检查代码兼容性
//    - 使用 jdeps 检查内部 API
//    - 使用 jdeprscan 检查废弃 API
//    - 检查编译错误
//
// 3. 更新构建工具
//    - 更新 Maven/Gradle 版本
//    - 更新编译配置
//
// 4. 更新第三方库
//    - 检查库兼容性
//    - 更新到支持 JDK 17 的版本
//
// 5. 修复代码
//    - 迁移内部 API
//    - 更新废弃 API
//    - 修复编译错误
//
// 6. 运行测试
//    - 单元测试
//    - 集成测试
//    - 性能测试
//
// 7. 部署验证
//    - 部署到测试环境
//    - 充分测试
//    - 部署到生产环境

迁移检查清单能帮你系统化地迁移。

注意事项

注意事项一:逐步迁移

建议逐步迁移,不要一次性升级:

// 逐步迁移
// 1. 先在测试环境测试
// 2. 逐步迁移模块
// 3. 充分测试
// 4. 最后迁移生产环境

逐步迁移能降低风险。

注意事项二:充分测试

迁移后要充分测试:

// 充分测试
// 1. 功能测试:确保功能正常
// 2. 性能测试:验证性能不下降
// 3. 兼容性测试:验证兼容性
// 4. 压力测试:验证稳定性

充分测试确保迁移成功。

注意事项三:回滚计划

准备回滚计划:

// 回滚计划
// 1. 保留旧版本代码
// 2. 准备回滚脚本
// 3. 测试回滚流程
// 4. 准备应急方案

准备回滚计划,以防万一。

最佳实践

最佳实践一:制定迁移计划

制定详细的迁移计划:

// 迁移计划
// 1. 评估迁移工作量
// 2. 制定时间表
// 3. 分配任务
// 4. 设置里程碑

制定详细的迁移计划,确保迁移顺利进行。

最佳实践二:使用工具检查

使用工具检查依赖和兼容性:

# 使用工具检查
# 1. jdeps:检查内部 API 依赖
# 2. jdeprscan:检查废弃 API
# 3. 编译测试:检查编译错误

使用工具检查,及时发现问题。

最佳实践三:文档记录

记录迁移过程和问题:

// 文档记录
// 1. 记录迁移步骤
// 2. 记录遇到的问题
// 3. 记录解决方案
// 4. 更新项目文档

记录迁移过程,方便后续维护。

总结

从 JDK 8/11 升级到 JDK 17 是个大工程,需要检查代码兼容性、更新第三方库、调整配置参数。这玩意儿虽然工作量不小,但 JDK 17 是 LTS 版本,性能和安全都有提升,值得升级。建议制定详细的迁移计划,逐步执行,充分测试,确保平滑升级。

建议在实际项目中尽早开始迁移,避免在 JDK 更新时出现问题。虽然迁移可能需要一些时间,但能让应用更稳定,性能更好。JDK 17 的新特性就介绍到这里了,兄弟们有啥问题随时问,鹏磊会尽量解答。

本文章最后更新于 2025-11-28