一、引言
"我们还在用 Java 8"——这句话在 2026 年听起来已经有些过时了。
根据 JDK 支持周期,Java 17 的免费支持将在 2026 年底到期。如果你还在使用 Java 8 或 11,现在就是开始规划迁移的最佳时机。
本文将深入分析三个必须迁移的理由,并提供一份详尽的迁移检查清单。
二、理由一:安全合规红线
2.1 JDK 支持周期
| JDK 版本 | 发布时间 | 免费支持截止 | 长期支持 (LTS) |
|---|---|---|---|
| Java 8 | 2014 | 2019 (Oracle) / 2030 (OpenJDK) | ✅ |
| Java 11 | 2018 | 2023 (Oracle) / 2026 (OpenJDK) | ✅ |
| Java 17 | 2021 | 2026 (Oracle) / 2029 (OpenJDK) | ✅ |
| Java 21 | 2023 | 2031 (预计) | ✅ |
2.2 为什么现在必须行动
Oracle JDK 用户:
- Java 8:2019 年已停止免费更新,继续使用存在安全风险
- Java 11:2023 年已停止免费更新
- Java 17:2026 年底停止免费更新
OpenJDK 用户(Eclipse Temurin、Amazon Corretto、Azul Zulu 等):
- Java 17:通常支持到 2029 年,但安全补丁更新频率会降低
- Java 21:最新 LTS,支持周期最长
2.3 安全风险案例
// 2024 年 Log4Shell 漏洞
// Java 8/11 需要紧急升级补丁
// Java 17+ 内置更强的安全机制
// 2025 年 Spring4Shell 漏洞
// 依赖 Spring Framework 版本
// 但旧版 JDK 无法运行新版 Spring
结论:不升级 = 安全裸奔。合规要求的红线就在眼前。
三、理由二:Virtual Threads 性能革命
3.1 什么是 Virtual Threads
Virtual Threads(虚拟线程)是 Java 21 引入的轻量级线程,由 JVM 管理,无需操作系统线程调度。
// 传统方式:10000 个请求需要 10000 个 OS 线程
ExecutorService executor = Executors.newFixedThreadPool(10000);
// 虚拟线程:10000 个请求只需要少量 OS 线程
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
3.2 性能对比
测试场景:HTTP 请求处理,每个请求包含 100ms 的数据库查询等待
| 线程模型 | 并发数 | OS 线程数 | CPU 使用率 | 吞吐量 (req/s) |
|---|---|---|---|---|
| 传统线程池 | 1000 | 1000 | 95% | 8,500 |
| 虚拟线程 | 1000 | 8 | 40% | 25,000 |
| 虚拟线程 | 10000 | 8 | 45% | 80,000 |
结论:在 IO 密集型场景下,吞吐量提升 3-5 倍,资源占用大幅降低。
3.3 ⚠️ 关键坑:Synchronized 会 Pin 虚拟线程
这是 Java 21 虚拟线程最容易踩的坑!
// ❌ 错误:synchronized 会导致虚拟线程被 Pin 到 Carrier Thread
public synchronized void process() {
// IO 操作期间,Carrier Thread 被阻塞
// 其他虚拟线程无法使用这个 Carrier Thread
}
// ✅ 正确:使用 ReentrantLock
private final ReentrantLock lock = new ReentrantLock();
public void process() {
lock.lock();
try {
// IO 操作期间,虚拟线程会被挂起
// Carrier Thread 可以处理其他虚拟线程
} finally {
lock.unlock();
}
}
原理:
- Java 21 中,
synchronized块会将虚拟线程固定(pin)到 Carrier Thread - 在 IO 等待期间,Carrier Thread 无法释放,导致资源浪费
- Java 24 的 JEP 491 已修复此问题
3.4 虚拟线程适用场景
| 场景 | 适用 | 原因 |
|---|---|---|
| HTTP 服务 | ✅ | 大量 IO 等待 |
| 消息队列消费 | ✅ | 大量等待消息 |
| 数据库查询 | ✅ | 大量等待响应 |
| CPU 密集计算 | ❌ | 无法利用虚拟线程优势 |
| 频繁 synchronized | ⚠️ | 需要改造 |
四、理由三:框架生态升级
4.1 Spring Boot 版本要求
| Spring Boot | 最低 Java 版本 | 推荐 Java 版本 |
|---|---|---|
| 2.7.x | 8 | 8/11 |
| 3.0.x | 17 | 17 |
| 3.2.x | 17 | 17/21 |
| 4.0.x(预计) | 17 | 21 |
注意:Spring Boot 4.x 最低要求 Java 17,推荐使用 Java 21,但不是强制要求 21。
4.2 升级路径
Java 8 → Java 17 → Java 21
↓ ↓
Spring Boot 2.7 → Spring Boot 3.2 → Spring Boot 3.2+
4.3 关键变化:javax → jakarta
这是 Spring Boot 3.x 迁移中最大的坑!
// Spring Boot 2.x (Java 8/11)
import javax.servlet.http.HttpServletRequest;
import javax.persistence.Entity;
import javax.validation.constraints.NotNull;
// Spring Boot 3.x (Java 17+)
import jakarta.servlet.http.HttpServletRequest;
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;
影响范围:
- Servlet API:
javax.servlet.*→jakarta.servlet.* - JPA/Hibernate:
javax.persistence.*→jakarta.persistence.* - Validation:
javax.validation.*→jakarta.validation.* - JMS:
javax.jms.*→jakarta.jms.*
五、迁移检查清单
5.1 废弃 API 扫描
使用 jdeps 工具:
# 扫描单个 JAR
jdeps --multi-release base --generate-report myapp.jar
# 扫描目录
jdeps --multi-release base -R --deprecated-list classes/
# 输出详细报告
jdeps --multi-release base -R --generate-report --html-output report/ myapp.jar
常见废弃 API:
| 废弃 API | 替代方案 |
|---|---|
java.util.Date | java.time.LocalDateTime |
java.sql.Date | java.time.LocalDate |
javax.xml.bind.* | jakarta.xml.bind.* |
sun.misc.Unsafe | VarHandle |
Thread.stop() | 中断机制 |
5.2 JVM 参数兼容性
| JVM 参数 | Java 8/11 | Java 17+ | 状态 |
|---|---|---|---|
-XX:+UseParallelGC | ✅ | ✅ | 保留 |
-XX:+UseG1GC | ✅ | ✅ | 推荐 |
-XX:+UseZGC | ❌ | ✅ | 新特性 |
-XX:+UseShenandoahGC | ❌ | ✅ | 新特性 |
-XX:MaxPermSize | ✅ | ❌ | 移除(元空间) |
-XX:+CMSParallelRemarkEnabled | ✅ | ❌ | 移除(CMS 废弃) |
-XX:+UnlockExperimentalVMOptions | ✅ | ✅ | 保留 |
5.3 框架版本升级路径
// pom.xml 升级示例
<!-- Spring Boot 2.7 → 3.2 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
</parent>
<!-- 数据库驱动版本升级 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>
<!-- Hibernate 版本升级 -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.4.4.Final</version>
</dependency>
<!-- Jackson 版本升级 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.1</version>
</dependency>
5.4 代码层面检查
# 1. 搜索 javax 引用
grep -r "import javax\." src/main/java/
# 2. 搜索 synchronized
grep -r "synchronized" src/main/java/
# 3. 搜索 Thread.stop()
grep -r "Thread\.stop()" src/main/java/
# 4. 搜索 sun.misc
grep -r "sun\.misc" src/main/java/
5.5 测试覆盖
@SpringBootTest
class MigrationTest {
@Test
void testJavaxToJakartaMigration() {
// 验证所有 javax 引用已迁移到 jakarta
// 使用反射检查类路径中是否还有 javax 类
}
@Test
void testVirtualThreadCompatibility() {
// 验证 synchronized 代码块不会导致性能问题
// 或已替换为 ReentrantLock
}
@Test
void testDeprecatedApiRemoval() {
// 验证没有使用废弃 API
}
}
六、灰度方案
6.1 分阶段迁移
阶段一:环境准备(1-2 周)
├── 搭建 Java 17/21 构建环境
├── 配置 CI/CD 多版本构建
└── 准备测试环境
阶段二:代码改造(2-4 周)
├── javax → jakarta 迁移
├── 废弃 API 替换
└── synchronized → ReentrantLock(可选)
阶段三:测试验证(2 周)
├── 单元测试全覆盖
├── 集成测试
└── 性能基准测试
阶段四:灰度发布(1-2 周)
├── 小流量验证(1%)
├── 中等流量验证(10%)
└── 全量上线
6.2 性能基准测试
# 使用 JMH 进行基准测试
mvn jmh:benchmark -Djmh.outputFormat=JSON
# 使用 JFR 记录性能数据
java -XX:StartFlightRecording=duration=30s,filename=profile.jfr \
-jar myapp.jar
# 使用 jcmd 分析
jcmd <pid> JFR.start duration=30s filename=profile.jfr
6.3 监控指标
| 指标 | 迁移前 | 迁移后(目标) |
|---|---|---|
| 响应时间 (P99) | 500ms | < 300ms |
| 吞吐量 | 1000 req/s | > 3000 req/s |
| 线程数 | 500 | < 50 |
| CPU 使用率 | 80% | < 50% |
| 内存占用 | 2GB | < 1.5GB |
七、总结
迁移决策矩阵
| 因素 | Java 8/11 | Java 17 | Java 21 |
|---|---|---|---|
| 安全支持 | ⚠️ 过期 | ✅ 到 2026 | ✅ 到 2031 |
| 虚拟线程 | ❌ | ❌ | ✅ |
| Spring Boot 3.x | ❌ | ✅ | ✅ |
| 学习成本 | 低 | 中 | 中 |
| 迁移难度 | 高 | 中 | 低(从 17 升级) |
行动建议
- 还在用 Java 8/11:立即开始规划迁移,目标 Java 17,再升级到 21
- 已经在 Java 17:评估虚拟线程收益,逐步迁移到 Java 21
- 新项目:直接使用 Java 21 + Spring Boot 3.2
核心要点
- 安全合规:Java 17 免费支持即将到期
- 性能提升:虚拟线程在 IO 密集型场景下提升 3-5 倍
- 框架生态:Spring Boot 3.x 要求 Java 17+,4.x 推荐 Java 21
- 注意坑点:synchronized 会 pin 虚拟线程,javax→jakarta 命名空间迁移
💡 互动话题:你们团队目前使用哪个 Java 版本?有没有迁移计划?欢迎在评论区分享你的经验!
