将基于 Oracle JDK 17 开发的 Spring Boot 3.2.12 项目迁移到 OpenJDK 17 环境
将基于 Oracle JDK 17 开发的 Spring Boot 3.2.12 项目迁移到 OpenJDK 17 环境是一个非常直接和常见的过程,因为两者在绝大多数场景下是完全兼容的。Spring Boot 3.2 本身的要求就是 JDK 17+,它并不区分 Oracle JDK 还是 OpenJDK。
你的改造工作主要集中在环境配置、构建工具和依赖管理上,而不是大量的代码修改。
以下是详细的步骤和注意事项:
1. 核心兼容性确认(通常没问题)
首先,最重要的是要明白:OpenJDK 是 Java SE 规范的开源参考实现,而 Oracle JDK 17 及以后版本正是由 OpenJDK 构建而来,并附加了一些非核心的商业功能。
从 JDK 11 以后,Oracle JDK 和 OpenJDK 在功能上几乎完全一致,尤其是对于绝大多数应用开发而言。因此,你的代码在编译和运行时几乎不需要任何修改。
2. 改造步骤
a. 开发与构建环境 (CI/CD)
-
更换 JDK:将你的本地开发机器、测试服务器以及 CI/CD 流水线(如 Jenkins, GitLab CI)上的 JDK 从 Oracle JDK 17 替换为 OpenJDK 17。
-
下载:可以从多个供应商获取 OpenJDK 17 二进制发行版,推荐选择:
-
Eclipse Temurin (推荐): https://adoptium.net/temurin/releases/
-
Amazon Corretto: https://aws.amazon.com/cn/corretto/
-
Azul Zulu: https://www.azul.com/downloads/
-
Microsoft Build of OpenJDK: https://www.microsoft.com/openjdk
-
-
这些发行版都经过了良好的测试,与 Oracle JDK 17 100% 兼容。
-
-
更新构建工具配置:
-
Maven:
确保你的pom.xml
中的maven-compiler-plugin
配置的<source>
和<target>
都是17
。xml
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.11.0</version><configuration><source>17</source><target>17</target><encoding>UTF-8</encoding></configuration> </plugin>
你也可以通过
properties
配置:xml
<properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><maven.compiler.release>17</maven.compiler.release> <!-- 推荐使用 release 参数 --> </properties>
-
Gradle:
在build.gradle
中确保编译选项正确:groovy
java {sourceCompatibility = '17'targetCompatibility = '17' }
-
b. Docker 化部署(如果适用)
如果你的项目通过 Docker 容器部署,需要将 Dockerfile 中的基础镜像从 Oracle JDK 镜像切换为 OpenJDK 镜像。
-
之前可能用的 (Oracle JDK):
dockerfile
FROM container-registry.oracle.com/java/jdk:17 ...
或者一些旧的
oracle/openjdk
镜像(已废弃)。 -
修改为 (OpenJDK):
强烈推荐使用 Eclipse Temurin 的镜像:dockerfile
FROM eclipse-temurin:17-jdk-jammy ...
或者使用其他供应商的镜像,如:
dockerfile
FROM amazoncorretto:17 ...
dockerfile
FROM azul/zulu-openjdk:17 ...
对于生产环境,通常建议使用 JRE 而不是完整的 JDK,以减少镜像大小和攻击面:
dockerfile
FROM eclipse-temurin:17-jre-jammy ...
注意:从 JDK 17 开始,Oracle 不再提供独立的 JRE 安装包,但大多数 OpenJDK 发行版(如 Temurin)仍然提供基于 JDK 的精简 JRE 镜像。
c. 检查特定依赖和功能
虽然极其罕见,但仍需检查你的项目是否使用了极其小众的、仅限 Oracle JDK 的商业特性:
-
Java Flight Recorder (JFR): 在 OpenJDK 17 中,JFR 已经是开源功能!你可以像在 Oracle JDK 中一样使用它。这是最大的一个变化,以前它是商业特性。
-
Java Mission Control (JMC): 虽然 JFR 开源了,但 JMC 工具本身是分开的。你需要从其他渠道获取 compatible 版本的 JMC。
-
其他商业特性: 如 Jaotc (AOT) 已经被移除,所以基本无需考虑。像 AppCDS 这类功能在 OpenJDK 发行版中通常也是可用的。
如果你的项目没有明确引入这些特性,那么你可以完全忽略这一点。
3. 验证测试
完成上述配置更改后,进行全面的测试是至关重要的。
-
本地测试:在安装好 OpenJDK 17 的本地环境中,运行
mvn clean compile
或gradle compileJava
确保编译通过。 -
单元测试:运行
mvn test
或gradle test
,确保所有单元测试通过。 -
集成测试/功能测试:启动应用,进行完整的端到端测试,确保所有核心功能正常。
-
性能测试(可选):如果你对性能有极致要求,可以进行简单的压测,对比在 OpenJDK 和 Oracle JDK 下的表现。但对于绝大多数应用,性能差异可以忽略不计。
总结
方面 | 改造动作 |
---|---|
JDK 安装包 | 将 Oracle JDK 17 替换为 OpenJDK 17 发行版(如 Eclipse Temurin 17) |
构建配置 | 确认 Maven/Gradle 的编译级别为 17 |
Docker 镜像 | 将基础镜像从 Oracle JDK 镜像改为 eclipse-temurin:17-jdk-jammy 或 eclipse-temurin:17-jre-jammy |
特性依赖 | (基本无需操作) 检查是否依赖极少数已不再受限的商业功能(大概率没有) |
测试 | 进行全面测试:编译、单元测试、功能测试 |
总而言之,这个迁移过程非常平滑,90% 的工作就是更换 JDK 安装包和 Docker 镜像,剩下的 10% 是充分的测试。 你可以自信地进行操作。
1. 核心 javax
包 vs. Java EE javax
包
首先要区分两种 javax
包:
-
核心
javax
包:例如javax.swing
(GUI工具包),javax.sql
(数据库连接),javax.security
(安全相关) 等。这些是 Java SE 平台的一部分,在 OpenJDK 17 中仍然存在。 -
Java EE / Jakarta EE
javax
包:例如javax.servlet
,javax.persistence
(JPA),javax.annotation
(如@PostConstruct
),javax.ejb
,javax.xml.bind
(JAXB) 等。这些原本是 Java 企业版平台的一部分。
2. 关键变化:JDK 9 的模块化 (JEP 320)
从 JDK 9 开始,Oracle 和 OpenJDK 社区通过 JEP 320 决定了一项重要变更:将 Java EE 和 CORBA 模块从 JDK 中移除。
这意味着:
-
在 JDK 8 中:这些 Java EE 的
javax
包是 随 JDK 一起分发 的。 -
在 JDK 9+(包括 JDK 17)中:这些 Java EE 的
javax
包 不再随 JDK 一起分发。如果你需要使用这些功能,你必须像添加其他第三方库一样,手动地将它们作为依赖项添加到你的项目中。
3. 这对 Spring Boot 3.2.12 项目意味着什么?
Spring Boot 3 是基于 Jakarta EE 9+ 的,这是一个关键信息!
-
命名空间迁移:Jakarta EE 9 进行了一个重大的更名,将所有
javax.*
包名都改为了jakarta.*
。-
例如:
javax.servlet
->jakarta.servlet
-
javax.persistence
->jakarta.persistence
-
-
Spring Boot 自动配置:Spring Boot starter(如
spring-boot-starter-web
)已经为你自动处理了这些依赖。当你引入spring-boot-starter-web
时,它会自动拉取正确版本的 Jakarta Servlet API (jakarta.servlet:jakarta.servlet-api
),你不需要再手动担心javax.servlet
的问题。
结论与操作指南
-
OpenJDK 17 有
javax
包吗?-
有:核心的
javax
包(如javax.swing
,javax.sql
)是存在的。 -
没有:企业级的
javax
包(如javax.servlet
)已从 JDK 中移除。
-
-
你的 Spring Boot 3.2.12 项目需要做什么?
-
代码中的
import
语句:检查你的代码。由于你使用的是 Spring Boot 3,所有之前对javax.*
(EE) 的导入都应该已经被改为jakarta.*
了。这是升级到 Spring Boot 3 的必要步骤。如果你的代码里还有import javax.servlet...
,那说明项目没有正确升级,需要改为import jakarta.servlet...
。 -
项目依赖:确保你的
pom.xml
或build.gradle
中的依赖都是正确的 Spring Boot 3 starters。Spring Boot 会帮你管理所有 Jakarta EE 依赖。你不需要也不应该手动添加旧的javax
依赖(如javax.servlet:javax.servlet-api
)。
-
-
如果遇到
ClassNotFoundException
或NoClassDefFoundError
怎么办?
这通常意味着你的某个依赖项还在尝试使用旧的javax
EE 包。你需要:-
升级这个依赖到与 Jakarta EE 9+ 兼容的版本。
-
或者,如果这个依赖没有新版本,你可以尝试添加一个适配器库(例如
org.eclipse.ee4j:jakartaee-api
),但这是一个临时方案,最好还是寻找替代依赖。
-
总结表格:
包类型 | 示例 | OpenJDK 17 中是否存在? | 在 Spring Boot 3 中如何获取? |
---|---|---|---|
核心 javax | javax.swing , javax.sql | 是 (JDK 内置) | JDK 自带,无需处理 |
Java EE javax | javax.servlet , javax.persistence | 否 (已从 JDK 移除) | 已过时,应使用对应的 jakarta.* 包 |
Jakarta EE | jakarta.servlet , jakarta.persistence | 否 (独立规范) | 通过 Spring Boot Starters 自动引入 |
因此,对于你的迁移,无需担心 javax
包的问题。你只需要确保项目正确使用了 jakarta.*
命名空间,并且依赖管理正确,OpenJDK 17 就能完美运行。
📦 javax.sql 包的核心成员
javax.sql
包从 JDK 1.4 开始就成为了 Java SE 平台的一部分,提供了许多用于访问和处理服务器端数据源的关键 API。
为了让你快速了解 javax.sql
包的核心内容,我整理了下面的表格:
类别 | 主要接口/类 | 说明 |
---|---|---|
核心接口 | DataSource | 替代 DriverManager 建立连接的工厂,是获取连接的首选方式。 |
连接池 | ConnectionPoolDataSource , PooledConnection | 支持连接池和语句池,可以显著提升性能。 |
分布式事务 | XADataSource , XAConnection | 支持分布式事务,允许在单个事务中涉及多个服务器上的数据源。 |
行集 (Rowsets) | RowSet , RowSetMetaData | 提供更灵活的方式来处理结果集,尤其适用于断开连接的环境。 |
🔄 与 Oracle JDK 的兼容性
在 javax.sql.DataSource
这个问题上,OpenJDK 17 和 Oracle JDK 17 的行为是完全一致的。两者都包含了标准的 javax.sql
包。
![[Pasted image 20240909092144.png]]
这意味着:
-
你的代码无需修改:所有依赖于
javax.sql.DataSource
的代码在 OpenJDK 17 上都能正常运行。 -
依赖关系不变:你不需要额外引入任何 JAR 包来弥补 JDK 本身的缺失。
⚠️ 注意事项:实现与使用
虽然接口是标准化的,但需要注意以下几点:
-
JDK 提供接口,而非实现:JDK 自带的
javax.sql.DataSource
只是一个接口,不是具体的实现。你需要通过第三方库(如 HikariCP、Apache Commons DBCP、Tomcat JDBC Pool 等)来获得实际的、功能完备的数据源和连接池实现。应用服务器(如 Tomcat, WildFly 等)通常会为你集成这些实现。 -
Spring Boot 的自动配置:如果你在使用 Spring Boot,它通常会自动配置一个高性能的连接池(如 HikariCP)。你只需要在
application.properties
或application.yml
中配置数据库连接字符串、用户名、密码等属性即可,Spring Boot 会帮你创建和管理实际的DataSource
实例。
💡 总结
-
你可以放心地在 OpenJDK 17 中使用
javax.sql.DataSource
,其行为与 Oracle JDK 17 无任何差异。 -
你看到的这个接口是 Java SE 的标准 API,并非来自 Java EE/Jakarta EE。
-
在实际项目中,你通常会通过配置第三方连接池库(或由 Spring Boot 等框架自动配置)来获得这个接口的具体实现。