1、概览 {#1概览}
在本教程中,我们将学习如何将 Spring Boot 应用迁移到 3.0 版本。当前所使用的 Spring Boot 版本是 2.7,并且 Java 版本是 17。
2、核心的变化 {#2核心的变化}
Spring Boot 3.0 是该框架的一个重要里程碑,对其核心组件进行了多项重要修改。
2.1、配置属性 {#21配置属性}
部分属性的修改:
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 获取。
该依赖会在启动时生成并打印一份报告,列出已废弃的属性名称,并在运行时临时迁移这些属性。
2.2、Jakarta EE 10 {#22jakarta-ee-10}
新版 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
语句。
2.3、Hibernate {#23hibernate}
如果我们未通过 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 获取。
2.4、其他变化 {#24其他变化}
此外,该版本还包括一些其他重大的核心变化:
- 移除图像 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
来指定哪个构造函数将用于属性绑定。
3、Web 应用的变化 {#3web-应用的变化}
如果我们的应用是一个 Web 应用,我们可能要进行一些更改。
3.1、尾斜线匹配 {#31尾斜线匹配}
新发布的 Spring Boot 废弃了配置"尾斜线匹配"的选项,并将其默认值设置为 false
。
例如,定义一个简单的 GET 端点:
@RestController
@RequestMapping("/api/v1/todos")
@RequiredArgsConstructor
public class TodosController {
@GetMapping("/name")
public List<String> findAllName(){
return List.of("Hello","World");
}
}
现在,GET /api/v1/todos/name/
默认情况下不再匹配,会导致 HTTP 404 错误。
我们可以通过定义一个实现 WebMvcConfigurer
或 WebFluxConfigurer
(响应式)的新配置类来启用所有端点的尾斜线匹配:
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
// 启用尾斜线匹配
configurer.setUseTrailingSlashMatch(true);
}
}
3.2、响应头大小限制 {#32响应头大小限制}
如前所述,server.max.http.header.size
属性已被弃用,取而代之的是 server.max-http-request-header-size
,它只检查请求头的大小。为了给响应头也定义一个限制,让我们定义一个新的 Bean:
@Configuration
public class ServerConfiguration implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setProperty("maxHttpResponseHeaderSize", "100000");
}
});
}
}
如果我们使用的是 Jetty 而不是 Tomcat,则应将 TomcatServletWebServerFactory 更改为 JettyServletWebServerFactory。此外,其他嵌入式 Web 容器并不支持这一功能。
3.3、其他变化 {#33其他变化}
此外,该版本在 web 应用层面也有其他重大变化:
- 优雅停机:优雅停机的
SmartLifecycle
实现更新了。现在,Spring 会在SmartLifecycle.DEFAULT_PHASE - 2048
阶段启动优雅停机,并在SmartLifecycle.DEFAULT_PHASE - 1024
阶段停止 Web 服务器。 RestTemplate
的HttpClient
:RestTemplate
更新了其 Apache HttpClient5 的版本。
4、Actuator 的变化 {#4actuator-的变化}
Actuator 模块中引入了一些重大变化。
4.1、Actuator 端点脱敏 {#41actuator-端点脱敏}
在以前的版本中,Spring 会自动屏蔽端点 /env
和 /configprops
上的敏感 key 值,这些端点会显示配置属性和环境变量等敏感信息。在此版本中,Spring 更改了方法,默认情况下更加安全。
现在,它不再只屏蔽某些 key 值,而是默认屏蔽所有 key 值。我们可以通过设置 management.endpoint.env.show-values
(适用于 /env
端点)或 management.endpoint.configprops.show-values
(适用于 /configprops
端点)的属性值来更改这一配置。可选值如下:
NEVER
:不显示值ALWAYS
:显示所有值。WHEN_AUTHORIZED
:如果用户已获授权,则会显示所有值。对于 JMX,所有用户都已授权。对于 HTTP,只有特定角色可以访问数据。
4.2、其他变化 {#42其他变化}
Spring Actuator 模块上也有其他相关更新:
- Jmx 端点暴露:JMX 只处理
health
端点。通过配置management.endpoints.jmx.exposure.include
和management.endpoints.jmx.exposure.exclude
属性,我们可以对其进行自定义。 httptrace
端点重命名:此版本将/httptrace
端点重命名为/httpexchanges
。- 该版本现在隔离了负责序列化 actuator 端点响应的
ObjectMapper
实例。我们可以通过将management.endpoints.jackson.isolated-object-mapper
属性设置为false
来更改此功能。
5、Spring Security {#5spring-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
下的新属性。
6、Spring Batch {#6spring-batch}
让我们看看 Spring Batch 模块中引入的一些重大变化。
6.1、不建议使用 @EnableBatchProcessing {#61不建议使用-enablebatchprocessing}
以前,我们可以使用 @EnableBatchProcessing
对配置类进行注解,从而启用 Spring Batch 的自动配置功能。如果我们想使用自动配置,Spring Boot 的新版本不鼓励使用该注解。
实际上,使用这个注解(或定义一个实现 DefaultBatchConfiguration
的bean)会告诉 Spring 停止自动配置。
6.2、运行多个作业 {#62运行多个作业}
以前,使用 Spring Batch 可以同时运行多个批处理作业。但现在情况已不再如此。如果自动配置检测到单个作业,它将在应用程序启动时自动执行。
因此,如果 context 中有多个作业,我们就需要使用 spring.batch.job.name
属性提供作业的名称,从而指定启动时应执行哪个作业。因此,这意味着如果我们要运行多个作业,就必须为每个作业创建一个单独的应用程序。
或者,我们也可以使用 Quartz、Spring Scheduler 或其他调度程序来调度作业。
7、总结 {#7总结}
在本文中,我们学习了 Spring Boot 3 中核心组件的变化,以及如何将 Spring Boot 2.7 应用迁移到 Spring Boot 3。
还有一些其他模块的变化,如 Spring Session、Micrometer、依赖管理等,可以参考 官方 Wiki。
参考:https://www.baeldung.com/spring-boot-3-migration