轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java

    • 核心

    • 并发

    • 经验

      • Java8升级到Java11的实践
        • 一、为什么升级?Java 8 不香了吗
          • 1、升级的核心驱动力
          • 1.1、性能提升
          • 1.2、新特性支持
          • 1.3、生态系统要求
          • 2、为何选择 Java 11 而非直接升级到 Java 17?
          • 2.1、渐进式升级策略
        • 二、升级实战指南
          • 1、升级前的准备工作
          • 1.1、依赖兼容性检查
          • 1.2、已删除功能的替代方案
          • 2、核心变更深度解析
          • 3、模块系统(JPMS)完全指南
          • 3.1、理解模块化带来的影响
          • 3.2、实战配置示例
          • 3.3、常见框架的模块配置
          • 4、统一 JVM 日志系统
          • 4.1、日志格式迁移对照表
          • 4.2、生产环境推荐配置
          • 4.3、日志解析示例
          • 5、三方库兼容性问题及解决方案
          • 5.1、常见依赖升级指南
          • 5.2、具体问题案例
          • a、Javassist 字节码生成问题
          • b、SSL/TLS 提供者冲突
          • c、接口默认方法反射调用
          • 6、JVM 参数迁移指南
          • 6.1、重要参数变化对照表
          • 6.2、快速检测工具
          • 6.3、生产环境 JVM 参数模板
        • 三、常见陷阱与最佳实践
          • 1、升级过程中的常见问题
          • 1.1、编译期问题
          • 1.2、运行期问题
          • 1.3、Docker 镜像问题
          • 2、升级检查清单
          • 3、性能优化建议
        • 四、总结
      • Java 11升级到Java 17及Spring Boot 3迁移实战指南
    • JVM

    • 企业应用

  • Spring

  • 其他语言

  • 工具

  • 后端
  • Java
  • 经验
轩辕李
2023-01-06
目录

Java8升级到Java11的实践

# 一、为什么升级?Java 8 不香了吗

# 1、升级的核心驱动力

# 1.1、性能提升

  • G1 垃圾收集器优化:Java 11 中 G1 成为默认 GC,相比 Java 8 的 Parallel GC,延迟降低 30-50%
  • 字符串优化:String 内部存储从 char[] 改为 byte[],Latin-1 字符串内存占用减少 50%
  • 启动性能:Application Class-Data Sharing (AppCDS) 可缩短启动时间 10-20%

# 1.2、新特性支持

  • 局部变量类型推断:var 关键字让代码更简洁
  • HTTP Client API:原生支持 HTTP/2,替代老旧的 HttpURLConnection
  • 集合工厂方法:List.of(), Set.of(), Map.of() 创建不可变集合
  • 字符串增强:isBlank(), lines(), strip(), repeat() 等实用方法

# 1.3、生态系统要求

  • Spring Boot 3.x 强制要求 Java 17+
  • 许多新版本库开始放弃 Java 8 支持
  • Oracle 已于 2022 年 3 月停止 Java 8 的公开更新

# 2、为何选择 Java 11 而非直接升级到 Java 17?

# 2.1、渐进式升级策略

Java 11 作为 LTS 版本,是从 Java 8 升级的理想跳板:

  • 风险可控:Java 9-11 的变化相对温和,Java 15 移除了 Nashorn JavaScript 引擎等重要组件
  • 兼容性更好:主流框架(如 Dubbo 2.x)对 Java 11 支持成熟,但对 Java 17 支持仍在完善
  • 迁移成本低:大部分 Java 8 代码可以在 Java 11 上直接运行,只需少量调整

# 二、升级实战指南

# 1、升级前的准备工作

# 1.1、依赖兼容性检查

使用 jdeps 工具扫描项目依赖:

jdeps --jdk-internals --multi-release 11 your-application.jar

# 1.2、已删除功能的替代方案

删除的功能 影响范围 替代方案
JavaFX GUI 应用 添加 OpenJFX 依赖:org.openjfx:javafx-base:11+
字体文件 POI、PDF 生成 Docker 镜像添加:RUN apt-get install -y fontconfig fonts-dejavu
Java Mission Control 性能监控 单独下载 JDK Mission Control (opens new window)
CORBA 模块 遗留系统集成 使用 GlassFish CORBA ORB 或迁移到 REST/gRPC
Java EE 模块 Web 应用 添加相应依赖,如 javax.xml.bind:jaxb-api:2.3.1

# 2、核心变更深度解析

# 3、模块系统(JPMS)完全指南

# 3.1、理解模块化带来的影响

Java 9 引入的模块系统是最大的架构变更,主要影响:

  • 反射访问限制:默认情况下无法反射访问其他模块的内部 API
  • 类路径变化:引入模块路径(module-path)概念
  • 强封装:sun.* 和 com.sun.* 包被强制封装

关于模块系统,参考:Java 模块系统 (opens new window)

这里补充一下--illegal-access参数,因为模块化的关系,如果模块中的软件包未导出或打开,但你仍然要使用这些软件包,可能会面临破坏应用程序的风险。如果在运行期反射调用内部API,可以通过添加--illegal-access=${value}来检查,它有四个值:

参数值 行为 使用场景 Java 17 兼容性
permit 首次违规时警告 Java 11 默认值,快速迁移 ❌ 已移除
warn 每次违规都警告 开发环境,发现所有问题 ❌ 已移除
debug 警告 + 堆栈信息 调试定位具体代码位置 ❌ 已移除
deny 禁止所有违规访问 生产环境,为 Java 17 做准备 ✅ 唯一选项

# 3.2、实战配置示例

渐进式迁移策略(推荐):

# 第一阶段:发现问题
java --illegal-access=warn -jar your-app.jar

# 第二阶段:逐个开放必要模块
java --illegal-access=deny \
  --add-opens java.base/java.lang=ALL-UNNAMED \
  --add-opens java.base/java.util=ALL-UNNAMED \
  --add-opens java.base/sun.nio.ch=ALL-UNNAMED \
  --add-exports java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED \
  -jar your-app.jar

# 第三阶段:针对特定框架的配置
# Spring Boot 应用
java --illegal-access=deny \
  --add-opens java.base/java.lang=ALL-UNNAMED \
  --add-opens java.base/java.lang.invoke=ALL-UNNAMED \
  -jar spring-boot-app.jar

# 3.3、常见框架的模块配置

# Hibernate/JPA
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.lang.invoke=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.base/java.nio=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED

# Netty
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED
--add-opens java.base/sun.nio.ch=ALL-UNNAMED

# Jackson
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/java.time=ALL-UNNAMED

# 4、统一 JVM 日志系统

# 4.1、日志格式迁移对照表

Java 8 参数 Java 11 等效参数 说明
-XX:+PrintGC -Xlog:gc 基础 GC 日志
-XX:+PrintGCDetails -Xlog:gc* 详细 GC 日志
-XX:+PrintGCDateStamps -Xlog:gc*::time 添加时间戳
-XX:+PrintGCApplicationStoppedTime -Xlog:safepoint STW 时间
-Xloggc:gc.log -Xlog:gc*:file=gc.log 输出到文件

# 4.2、生产环境推荐配置

# 基础配置:GC + 安全点日志
-Xlog:gc*,safepoint:file=/data/logs/jvm/gc.log:time,uptime,level,tags:filecount=10,filesize=100M

# 高级配置:包含更多诊断信息
-Xlog:gc*=info,safepoint=info,gc+ref=debug,gc+ergo=trace,gc+age=trace:file=/data/logs/jvm/gc-%t.log:time,uptime,pid,tid,level,tags:filecount=10,filesize=100M

# 性能调优配置:最小化日志开销
-Xlog:gc=info:file=/data/logs/jvm/gc.log::filecount=5,filesize=50M

# 4.3、日志解析示例

[2024-01-15T10:30:45.123+0800][0.456s][info][gc,start    ] GC(12) Pause Young (Normal) (G1 Evacuation Pause)
[2024-01-15T10:30:45.145+0800][0.478s][info][gc          ] GC(12) Pause Young (Normal) (G1 Evacuation Pause) 45M->12M(256M) 22.3ms

解析要点:

  • [时间戳][运行时长][日志级别][标签]:统一的日志格式
  • GC(12):第 12 次 GC
  • 45M->12M(256M):堆内存从 45M 降到 12M,总大小 256M
  • 22.3ms:GC 耗时

# 5、三方库兼容性问题及解决方案

# 5.1、常见依赖升级指南

库名称 Java 8 版本 Java 11 最低版本 说明
Spring Boot 2.x 2.2.0+ 2.1.x 部分支持
Spring Framework 5.0.x 5.1.0+ 完全支持模块系统
Hibernate 5.2.x 5.3.7+ 支持 Java 11 字节码
Jackson 2.8.x 2.10.0+ 修复反射访问问题
Lombok 1.16.x 1.18.4+ 支持 Java 11 编译
Mockito 2.x 2.23.0+ 支持新的字节码格式
Byte Buddy 1.8.x 1.9.0+ 动态代理兼容
ASM 6.x 7.0+ 字节码操作支持

# 5.2、具体问题案例

# a、Javassist 字节码生成问题

问题:CtClass.toClass() 方法签名变更

// Java 8 写法(已废弃)
ctClass.toClass(classLoader, neighborClass.getProtectionDomain());

// Java 11 写法
ctClass.toClass(neighborClass);

解决方案:升级到 Javassist 3.24.0+ 或修改调用方式

# b、SSL/TLS 提供者冲突

问题:javax.net.ssl.SSLProtocolException: Cannot decode named group: x25519

// 问题代码(某些旧版加密库)
Security.removeProvider("SunEC");  // 不要这样做!

解决方案:

  • 升级加密库到支持 Java 11 的版本
  • 使用 --add-exports 导出必要的安全模块
  • 避免移除系统安全提供者
# c、接口默认方法反射调用

问题:不同 Java 版本的 MethodHandle API 变化

// Java 8 方式
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
    .getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true);

// Java 11 方式(需要开放模块)
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(
    targetClass, MethodHandles.lookup());
MethodHandle handle = lookup.findSpecial(
    interfaceClass, methodName, methodType, targetClass);

解决方案:使用条件编译或升级到统一的反射库

# 6、JVM 参数迁移指南

# 6.1、重要参数变化对照表

Java 8 参数 Java 11 替代 影响说明
-XX:+UseConcMarkSweepGC -XX:+UseG1GC CMS 已废弃,G1 成为默认
-XX:+PrintGC -Xlog:gc 统一日志系统
-XX:+PrintGCDetails -Xlog:gc* 详细 GC 日志
-XX:+UnlockCommercialFeatures 无需 JFR 已免费
-XX:+FlightRecorder 默认可用 无需解锁
-XX:MaxPermSize 已移除 元空间自动管理
-XX:PermSize 已移除 使用 -XX:MetaspaceSize

# 6.2、快速检测工具

# 检测 JVM 参数兼容性
java -XX:+PrintCommandLineFlags -version

# 使用 JaCoLine 在线检测
# 访问 https://jacoline.dev/inspect 上传你的启动脚本

# 6.3、生产环境 JVM 参数模板

# Java 11 生产环境推荐配置
java -server \
  -Xms4g -Xmx4g \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:G1HeapRegionSize=16m \
  -XX:+ParallelRefProcEnabled \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+UnlockDiagnosticVMOptions \
  -XX:+AlwaysPreTouch \
  -XX:+UseStringDeduplication \
  -XX:+DisableExplicitGC \
  -XX:MetaspaceSize=256m \
  -XX:MaxMetaspaceSize=512m \
  -Xlog:gc*:file=/logs/gc.log:time,uptime,level,tags:filecount=10,filesize=100M \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath=/logs/heapdump.hprof \
  -XX:ErrorFile=/logs/hs_err_pid%p.log \
  -jar your-application.jar

# 三、常见陷阱与最佳实践

# 1、升级过程中的常见问题

# 1.1、编译期问题

问题 原因 解决方案
package javax.xml.bind does not exist JAXB 已从 JDK 移除 添加依赖:javax.xml.bind:jaxb-api:2.3.1
cannot find symbol: class Generated javax.annotation 包移除 添加:javax.annotation:javax.annotation-api:1.3.2
illegal reflective access 警告 模块系统限制 使用 --add-opens 参数
Maven 编译失败 插件版本过旧 升级 maven-compiler-plugin 到 3.8.0+

# 1.2、运行期问题

// 问题:ClassNotFoundException: sun.misc.BASE64Encoder
// Java 8 代码
import sun.misc.BASE64Encoder;
BASE64Encoder encoder = new BASE64Encoder();
String encoded = encoder.encode(data);

// Java 11 解决方案
import java.util.Base64;
String encoded = Base64.getEncoder().encodeToString(data);

# 1.3、Docker 镜像问题

# 问题:Alpine Linux 缺少字体导致 POI 等库报错
FROM openjdk:11-jre-alpine

# 解决方案:安装必要的系统库
RUN apk add --no-cache \
    fontconfig \
    ttf-dejavu \
    && rm -rf /var/cache/apk/*

# 或使用完整的基础镜像
FROM openjdk:11-jre-slim

# 2、升级检查清单

  • [ ] 依赖检查

    • 运行 mvn dependency:tree 查看所有依赖版本
    • 使用 jdeps 扫描内部 API 使用情况
    • 更新所有不兼容的依赖到支持 Java 11 的版本
  • [ ] 代码审查

    • 搜索并替换 sun.* 和 com.sun.* 包的使用
    • 检查反射代码,添加必要的模块开放参数
    • 替换已废弃的 API 调用
  • [ ] 构建配置

    • 更新 Maven/Gradle 插件版本
    • 设置正确的源码和目标版本
    • 配置模块路径(如果使用模块系统)
  • [ ] 运行时配置

    • 迁移 JVM 参数到新格式
    • 配置日志输出路径和格式
    • 添加必要的 --add-opens 和 --add-exports
  • [ ] 测试验证

    • 运行完整的单元测试套件
    • 执行集成测试和性能测试
    • 在预生产环境进行充分验证

# 3、性能优化建议

  1. G1GC 调优

    -XX:+UseG1GC
    -XX:MaxGCPauseMillis=200
    -XX:G1ReservePercent=15
    -XX:InitiatingHeapOccupancyPercent=45
    
  2. 字符串去重

    -XX:+UseStringDeduplication
    -XX:StringDeduplicationAgeThreshold=3
    
  3. AppCDS 应用

    # 生成类列表
    java -XX:DumpLoadedClassList=classes.lst -jar app.jar
    # 创建共享归档
    java -Xshare:dump -XX:SharedClassListFile=classes.lst -XX:SharedArchiveFile=app.jsa
    # 使用共享归档启动
    java -Xshare:on -XX:SharedArchiveFile=app.jsa -jar app.jar
    

# 四、总结

从 Java 8 升级到 Java 11 是一个值得投入的技术改造:

✅ 性能提升显著:G1 GC 优化、字符串内存优化等带来 20-30% 的性能提升
✅ 代码更加简洁:var 关键字、集合工厂方法、字符串新 API 提升开发效率
✅ 为未来做准备:作为 LTS 版本的跳板,便于后续升级到 Java 17/21

升级过程中最关键的是:

  1. 做好充分的兼容性测试
  2. 渐进式迁移,先在开发环境验证
  3. 合理使用模块系统的开放参数
  4. 及时更新三方依赖版本

记住,升级不是目的,持续演进才能保持技术栈的活力!

祝你变得更强!

编辑 (opens new window)
上次更新: 2025/08/15
Java并发-调试与诊断
Java 11升级到Java 17及Spring Boot 3迁移实战指南

← Java并发-调试与诊断 Java 11升级到Java 17及Spring Boot 3迁移实战指南→

最近更新
01
AI时代的编程心得
09-11
02
Claude Code与Codex的协同工作
09-01
03
Claude Code实战之供应商切换工具
08-18
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式