将 Spring Boot 2 应用迁移到 Spring Boot 3

更新于 2025-12-30

baeldung 2025-12-03

1. 概述

在本教程中,我们将学习如何将 Spring Boot 应用程序升级到 3.0 版本。要成功迁移至 Spring Boot 3,必须确保当前使用的 Spring Boot 版本为 2.7,且 Java 版本为 17

2. 核心变更

Spring Boot 3.0 是该框架的一个重要里程碑,对其核心组件进行了多项重大修改。

2.1 配置属性(Configuration Properties)

部分配置属性的键名已更改:

  • 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

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

如果我们通过排除 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 其他变更

此外,本次发布还包含以下重要的核心层变更:

  • 图像横幅(Image banner)支持被移除:现在仅支持通过 banner.txt 文件定义自定义横幅。
  • 日志日期格式器:Logback 和 Log4J2 的默认日期格式现为 yyyy-MM-dd’T’HH:mm:ss.SSSXXX。如果希望恢复旧格式,需在 application.yaml 中设置 logging.pattern.dateformat 属性。
  • @ConstructorBinding 仅作用于构造函数级别:对于 @ConfigurationProperties 类,不再需要在类级别上使用 @ConstructorBinding,应将其移除。但如果类或 record 有多个构造函数,则必须在目标构造函数上使用 @ConstructorBinding 来指定用于属性绑定的构造函数。

3. Web 应用变更

假设我们的应用是一个 Web 应用,还需考虑以下变更。

3.1 尾部斜杠匹配配置

新版本弃用了尾部斜杠匹配的配置选项,并默认将其设为 false

例如,定义一个简单的控制器:

@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 响应头大小限制

如前所述,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 其他变更

Web 应用层面还有以下重要变更:

  • 优雅关闭阶段调整SmartLifecycle 实现的优雅关闭阶段已更新。Spring 现在在 SmartLifecycle.DEFAULT_PHASE – 2048 阶段启动优雅关闭,并在 SmartLifecycle.DEFAULT_PHASE – 1024 阶段停止 Web 服务器。

4. Actuator 变更

Actuator 模块引入了一些重要变更。

4.1 Actuator 端点数据脱敏

在旧版本中,Spring Framework 会自动对 /env/configprops 端点中某些敏感键的值进行掩码处理。而在新版本中,Spring 默认对所有键的值进行掩码,以增强安全性。

可通过以下属性自定义行为:

  • management.endpoint.env.show-values(用于 /env 端点)
  • management.endpoint.configprops.show-values(用于 /configprops 端点)

可选值包括:

  • NEVER:不显示任何值
  • ALWAYS:显示所有值
  • WHEN_AUTHORIZED:仅在用户授权时显示所有值(JMX 下所有用户均视为授权;HTTP 下需特定角色)

4.2 其他变更

  • JMX 端点暴露:JMX 默认仅暴露 health 端点。可通过 management.endpoints.jmx.exposure.include/exclude 自定义。
  • httptrace 端点重命名/httptrace 已重命名为 /httpexchanges
  • 独立的 ObjectMapper:Actuator 端点的响应序列化现在使用独立的 ObjectMapper 实例。可通过设置 management.endpoints.jackson.isolated-object-mapper=false 禁用此行为。

5. Spring 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。

本版本引入了若干重要变更:

  • ReactiveUserDetailsService 不再自动配置:当存在 AuthenticationManagerResolver 时,不再自动配置 ReactiveUserDetailsService
  • SAML2 依赖方配置变更:此前位于 spring.security.saml2.relyingparty.registration.{id}.identity-provider 下的属性已不再支持。应改用新属性 spring.security.saml2.relyingparty.registration.{id}.asserting-party

6. Spring Batch

Spring Batch 模块也引入了若干重要变更。

6.1 @EnableBatchProcessing 不再推荐使用

过去可通过在配置类上添加 @EnableBatchProcessing 注解启用 Spring Batch 的自动配置。但在新版本中,若希望使用自动配置,则不建议使用此注解

实际上,使用该注解(或定义实现了 DefaultBatchConfiguration 的 Bean)会导致自动配置“退避”(back off)。

6.2 多作业(Jobs)执行方式变更

过去可同时运行多个批处理作业。但新版本中,若自动配置检测到上下文中存在单个作业,则会在应用启动时自动执行。

若上下文中存在多个作业,则必须通过 spring.batch.job.name 属性指定启动时要执行的作业名称。因此,若需运行多个作业,应为每个作业创建独立的应用程序。

或者,也可使用 Quartz、Spring Scheduler 等调度器来安排作业执行。

7. HttpClient 变更

Spring Boot 3 将其内部 HTTP 栈升级为使用 Apache HttpClient 5.x,取代了旧版的 4.x。因此,若应用通过 RestTemplateHttpComponentsClientHttpRequestFactory 自定义 HTTP 客户端,则需更新配置。

此升级引入了多项破坏性变更,尤其在 HttpClient 5.4 及更高版本中,采用了基于构建器(builder-based)的配置方式,并更紧密地对齐 Java 标准安全 API。

7.1 使用 HttpClient 4.x 的旧配置(已失效)

升级前的典型配置如下:

@Configuration
public class RestTemplateConfiguration {
    @Bean
    public RestTemplate getRestTemplate() {
        CloseableHttpClient httpClient = HttpClients.custom().build();

        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        requestFactory.setConnectTimeout(30000);
        requestFactory.setReadTimeout(30000);
        requestFactory.setConnectionRequestTimeout(30000);

        return new RestTemplate(requestFactory);
    }
}

但在 Spring Boot 3 中,此方式因与 HttpClient 5 不兼容而失效。

7.2 为何在 Spring Boot 3 中失效

基于 Apache HttpClient 4.x 的自定义 HTTP 配置与 Spring Boot 3 所依赖的 HttpClient 5.x 不兼容,主要问题包括:

  • HttpComponentsClientHttpRequestFactory 现在期望传入 5.x 的 CloseableHttpClient,而非 4.x 版本。
  • setConnectTimeout()setReadTimeout() 等超时方法已被弃用或静默忽略。
  • 运行时可能出现 NoSuchMethodErrorClassNotFoundExceptionorg.apache.http.* 类不兼容等问题。

这是因为底层 API 已被重新设计,而不仅仅是重构。例如,大多数类已从 org.apache.http.*(4.x)迁移到 org.apache.hc.*(5.x),且配置模型转向了构建器风格,并更贴近 Java 原生 SSL 概念。

为确保兼容性,必须更新依赖并重构 HTTP 客户端配置以匹配 HttpClient 5.x 的新 API。

7.3 迁移到 HttpClient 5.x(5.4 之前版本)

对于 5.4 之前的版本,可使用如下配置:

@Configuration
public class RestTemplateConfiguration {
    @Bean
    public RestTemplate restTemplate() {
        RequestConfig config = RequestConfig.custom()
          .setConnectTimeout(Timeout.ofSeconds(30))
          .setResponseTimeout(Timeout.ofSeconds(30))
          .setConnectionRequestTimeout(Timeout.ofSeconds(30))
          .build();
        CloseableHttpClient client = HttpClients.custom()
          .setDefaultRequestConfig(config)
          .build();
        return new RestTemplate(new HttpComponentsClientHttpRequestFactory(client));
    }
}

同时,需更新依赖:

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
</dependency>

7.4 迁移到 HttpClient 5.4 及更高版本

从 HttpClient 5.4 开始,Apache 引入了更现代化、模块化的配置模型,更贴近 Java 平台 API,并弃用了如 setConnectTimeout()setSSLHostnameVerifier() 等方法。客户端配置现在依赖构建器 API,提供更清晰的连接池、超时设置和扩展机制。

以下示例展示了如何使用 HttpClient 5.4+ 配置 RestTemplate

@Configuration
public class RestTemplateConfiguration {
    @Bean
    public RestTemplate restTemplate() {
        try {
            // 超时配置
            SocketConfig socketConfig = SocketConfig.custom()
              .setSoTimeout(Timeout.ofSeconds(30))  // 读取超时
              .build();

            ConnectionConfig connectionConfig = ConnectionConfig.custom()
              .setConnectTimeout(Timeout.ofSeconds(30))  // 连接超时
              .build();

            RequestConfig requestConfig = RequestConfig.custom()
              .setConnectionRequestTimeout(Timeout.ofSeconds(30))  // 连接池等待超时
              .build();

            // 连接池配置
            PoolingHttpClientConnectionManager connectionManager =
              PoolingHttpClientConnectionManagerBuilder.create()
                .setMaxConnPerRoute(20)
                .setMaxConnTotal(100)
                .setDefaultSocketConfig(socketConfig)
                .setDefaultConnectionConfig(connectionConfig)
                .build();

            CloseableHttpClient httpClient = HttpClients.custom()
              .setConnectionManager(connectionManager)
              .setDefaultRequestConfig(requestConfig)
              .build();

            return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
        } catch (Exception e) {
            throw new IllegalStateException("Failed to configure RestTemplate", e);
        }
    }
}

此新方法的关键变化包括:

  • 超时配置:使用 Timeout API 在 SocketConfigConnectionConfigRequestConfig 中设置,取代旧的 setter 方法。
  • 连接池:推荐使用 PoolingHttpClientConnectionManagerBuilder 构建器,而非直接实例化 PoolingHttpClientConnectionManager
  • 构建器风格配置:整体 API 设计更符合现代 Java 风格,强调关注点分离和更好的可扩展性。

通过迁移到此新配置模型,应用不仅能完全兼容 Spring Boot 3,还能受益于 HttpClient 5.4+ 引入的模块化、清晰性和安全性改进。

8. 结论

本文介绍了如何将 Spring Boot 2.7 应用迁移到 3.0 版本,重点涵盖了 Spring 环境的核心组件变更。此外,Spring Session、Micrometer、依赖管理等模块也发生了若干变化。