自从 JDK 8 发布以来,Java 语言在持续进化,带来了许多新的功能和性能改进。而 JDK 17 作为一个长期支持版本(LTS),在许多方面超越了 JDK 8,不仅提升了语言本身的能力,还进一步提高了性能、可维护性和开发者体验。
1 背景与功能增强
公司核心系统当前基于:
- JDK 1.8
- Spring Boot 2.x / Spring Cloud 2021.x
官方已于 2022 年宣布:
Spring Framework 6、Spring Boot 3、Spring Cloud 2022+ 最低要求 JDK 17 。
继续留在 JDK 8 将永久锁定在 2.x 维护分支,无法获得任何新特性与安全补丁。
1.Spring 官方强制基线
- Spring Framework 6.x:仅支持 JDK 17+
- Spring Boot 3.x:最低 JDK 17,默认内置 Native/CDS 优化
- Spring Cloud 2022+:基于 Boot 3,提供 Gateway 4、K8s Config 2.0 等新组件
停留在 JDK 8 = 永久错过新功能与社区长期维护。
2.模块化系统(JDK 9 引入,JDK 17 强化)
在 JDK 9 中引入了 Java 平台的模块化系统,它通过 module
关键字帮助开发者将代码组织成不同的模块,从而提升代码的可维护性、可扩展性和安全性。JDK 17 在模块系统方面进行了更多优化,使得模块化的使用更加高效。
- JDK 8:没有模块化系统,所有代码都在一个大的类库中。
- JDK 17:模块化系统已经成熟,Java 平台本身被拆分为多个模块,可以灵活选择需要的模块,大大减少了 JDK 的体积,提高了应用的启动性能。
示例代码:
module com.myapp {
requires java.base;
exports com.myapp.service;
}
3.Lambda 表达式与 Stream API(JDK 8 引入)
JDK 8 引入了 Lambda 表达式和 Stream API,极大简化了函数式编程和集合操作的语法。JDK 17 在此基础上优化了性能和流操作的稳定性,尤其在处理大量数据时,提供了更好的支持。
- JDK 8:Lambda 表达式和 Stream API 支持函数式编程,简化了集合的操作。
- JDK 17:增强了 Stream API 和 Lambda 表达式的性能,特别是在并行流操作和垃圾回收方面。
4.记录类(JDK 14 引入)
JDK 14 引入了记录类(record
),这是一个简化 Java Bean 类的语法。它使得不需要编写大量的模板代码(如 getter、setter、equals、hashCode 等方法)。在 JDK 17 中,记录类的支持变得更加完善,尤其是对继承和序列化的支持。
- JDK 8:没有记录类,需要手动编写 getter、setter、equals 和 hashCode 方法。
- JDK 17 :使用
record
关键字定义不可变对象,自动生成常用方法,减少样板代码,提高可读性。
示例代码:
public record Person(String name, int age) {}
5.增强的 switch
表达式(JDK 12 引入)
JDK 12 引入了增强的 switch
表达式,这使得 switch
更加灵活,支持返回值、块语句和 yield
语句。JDK 17 中进一步优化了 switch
表达式的性能和功能,提升了代码的可维护性。
- JDK 8 :
switch
只能用作控制结构,无法返回值或执行多条语句。 - JDK 17 :增强的
switch
表达式允许返回值、使用块语句,并支持yield
语句来返回结果
示例代码:
int day = 3;
String result = switch (day) {
case 1 -> "Sunday";
case 2 -> "Monday";
default -> throw new IllegalStateException("Invalid day: " + day);
};
6、var
关键字(JDK 10 引入)
JDK 10 引入了 var
关键字,允许在声明变量时让编译器根据初始化值推断类型。这大大减少了样板代码,增强了代码的简洁性和可读性。在 JDK 17 中,var
关键字支持了更多的上下文,进一步简化了代码。
- JDK 8 :没有
var
关键字,所有变量都必须显式声明类型。 - JDK 17 :
var
关键字被广泛应用于局部变量声明和增强的 lambda 表达式中,减少了冗余的类型声明。
示例代码:
var message = "Hello, Java!";
var list = new ArrayList<String>();
7.JVM 性能与垃圾回收改进
JDK 8 和 JDK 17 在 JVM 性能和垃圾回收(GC)方面有显著差异。JDK 17 默认启用了更先进的垃圾回收器(例如 G1 GC 和 ZGC),这些改进使得内存管理更加高效,并减少了 GC 停顿时间。
- JDK 8 :默认使用
Parallel GC
,适用于大部分应用场景,但在响应时间要求高的场景下可能表现不佳。 - JDK 17 :引入了
ZGC
(Z Garbage Collector),在低延迟应用中表现优异,能够处理非常大的堆内存。
8.、文本块(JDK 13 引入)
JDK 13 引入了文本块(text block
)功能,这使得多行字符串文本的编写变得更加简洁和可读。文本块支持原始文本格式,使得嵌套 JSON 或 SQL 查询变得更加直观。
- JDK 8 :多行字符串需要使用字符串连接符
+
,使得代码不易阅读。 - JDK 17 :支持多行字符串文本(
text block
),大大提升了代码的可读性和简洁性。
示例代码:
String json = """
{
"name": "John",
"age": 30,
"city": "New York"
}
""";
9.增强的 Pattern
和 Matcher
API(JDK 16 引入)
JDK 16 引入了对正则表达式的增强支持,尤其是 Pattern
和 Matcher
类的增强,使得在处理复杂的正则表达式时更加灵活和高效。
- JDK 8:正则表达式库功能较为基础。
- JDK 17:增强了正则表达式的语法支持,包括非捕获分组和更复杂的匹配模式。
10.sealed
类(JDK 15 引入)
sealed
类(密封类)是在 JDK 15 中引入的一个特性,它允许类设计者限制哪些类可以继承它们。这个特性为 Java 提供了更强的类型系统,能够确保类层次结构的封闭性。
- JDK 8 :没有
sealed
类,所有类可以自由继承。 - JDK 17 :支持
sealed
类,类设计者可以限制子类的继承,从而增强代码的可控性和安全性。
示例代码:
public sealed class Shape permits Circle, Square {}
public final class Circle extends Shape {}
public final class Square extends Shape {}
11.JEP 389:外部内存访问 API(JDK 16 引入)
JDK 16 引入了外部内存访问 API,它为 Java 提供了一种更高效的方式来访问外部内存(即不在 Java 堆中的内存),这个特性对于与本地代码或操作系统交互时的性能优化非常重要。
- JDK 8:不提供对外部内存的直接访问。
- JDK 17 :通过
MemorySegment
和MemoryAddress
等 API,Java 现在可以更高效地与外部内存交互。
2 升级计划
整个升级过程 计划分为3步。
- step1:先将项目升级到jdk17,使用正常
- step2:生成代码的模板类升级到Jdk17对应的版本
- step3:功能陆续验证
原项目版本:Jdk8 + springboot 2.x.x.x
升级后版本:Jdk17 + springboot 3.x.x
2.1 基础依赖升级
1. 首先把项目环境切换到Jdk17上

2. 父级pom文件中spring-boot-starter-parent
版本升级到3.x.x
<properties>
<spring.boot.version>3.1.0</spring.boot.version>
</properties>
3. 项目配置中的java.version
由8升级到17
<properties>
<java.version>17</java.version>
</properties>
4. maven编译相关maven.compiler.source
、maven.compiler.target
由8升到17
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
5. 由于在jdk17中移除了javax的部分包,所以很多javax.xxx都需要修改jakarta.xxx
新版 Jakarta EE 10 对 Spring Boot 3 的相关依赖进行了更新:
- Servlet 规范更新至 6.0。
- JPA 规范更新至 3.1。
因此,如果我们未通过 spring-boot-starter
来自动管理这些依赖的版本,我们就应该手动更新它们。
首先更新 JPA 依赖:
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.1.0</version>
</dependency>
最新版本的 jakarta.persistence-api 可从 Maven Central 获取。
接下来更新 Servlet 依赖:
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
</dependency>
最新版本的 jakarta.servlet-api 可从 Maven Central 获取。
除了依赖坐标的变化外,Jakarta EE 现在使用 jakarta
包而不是 javax
包。因此,更新依赖后,我们可能需要更新 import
语句。
6. 如果我们未通过 spring-boot-starter
来管理 Hibernate 的依赖版本,那么一定要手动更新其版本:
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.1.4.Final</version>
</dependency>
最新版本的 hibernate-core 可从 Maven Central 获取。
7. lombok版本由1.18.20 升级 1.18.30
2.2 相关组件升级
部分属性的修改:
部分属性的修改:
spring.redis
已移至spring.data.redis
。spring.data.cassandra
已移至spring.cassandra
。- 移除了
spring.jpa.hibernate.use-new-id-generator
。 server.max.http.header.size
已移至server.max-http-request-header-size
。- 移除了对
spring.security.saml2.relyingparty.registration.{id}.identity-provider
的支持。
要识别这些属性,我们可以在 pom.xml
中添加 spring-boot-properties-migrator
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
最新版本的 spring-boot-properties-migrator 可从 Maven Central 获取。
该依赖会在启动时生成并打印一份报告,列出已废弃的属性名称,并在运行时临时迁移这些属性。
其他变化
此外,该版本还包括一些其他重大的核心变化:
- 移除图像 banner 支持:要自定义 banner,只有
banner.txt
文件才被视为有效文件。 - 日志中的日期格式:Logback 和 Log4J2 的新默认日期格式为
yyyy-MM-dd'T'HH:mm:ss.SSSXXX
如果要恢复旧的默认格式,我们需要将application.yaml
中的属性logging.pattern.dateformat
的值设置为旧值。 @ConstructorBinding
只在构造函数上使用:对于@ConfigurationProperties
类,不再需要在类上使用@ConstructorBinding
,并且应该将其移除。然而,如果一个 class 或 record 有多个构造函数,则必须在所需的构造函数上使用@ConstructorBinding
来指定哪个构造函数将用于属性绑定。
security
Spring Boot 3 仅与 Spring Security 6兼容。
在升级到 Spring Boot 3.0 之前,我们应该先 将 Spring Boot 2.7 应用升级到Spring Security 5.8。然后,我们可以将 Spring Security 升级到版本 6,并升级到 Spring Boot 3.0。
该版本中引入了一些重要更改:
- ReactiveUserDetailsService 未自动配置:在存在 AuthenticationManagerResolver 的情况下,
ReactiveUserDetailsService
不再自动配置。 - SAML2 依赖方配置:我们之前提到,新版 Spring boot 不再支持
spring.security.saml2.relyingparty.registration.{id}.identity-provider
下的属性。相反,我们应该使用spring.security.saml2.relyingparty.registration.{id}.asserting-party
下的新属性。
3 版本对应
JDK版本与Spring Boot版本对应

Maven版本与Spring Boot版本对应

SpringCloud与SpringBoot版本对应

项目大致依赖

springcloud相关组件
