知識庫 / Spring / Spring Boot RSS 訂閱

從 Spring Boot 2 遷移到 Spring Boot 3

Spring Boot
HongKong
5
11:40 AM · Dec 06 ,2025

1. 概述

在本教程中,我們將學習如何將 Spring Boot 應用程序遷移到 3.0 版本。為了成功地將應用程序遷移到 Spring Boot 3,我們需要確保其當前的 Spring Boot 版本為 2.7,以及 Java 版本為 17。

2. 核心變更

Spring Boot 3.0 是該框架的一個重要里程碑,對其核心組件進行了數項重要的修改。

2.1. 配置屬性

以下是一些屬性鍵已被修改:

  • 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 支持已移除

要識別這些屬性,我們可以將 spring-boot-properties-migrator 添加到我們的 pom.xml 中:

<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

The new version of Jakarta EE 10 brings updates to the related dependencies of Spring Boot 3:

  • Servlet specification updated to version 6.0
  • JPA specification updated to version 3.1

So, if we’re managing those dependencies by excluding them from the <em >spring-boot-starter</em> dependency, we should make sure to update them.

Let’s start by updating the JPA dependency:

<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. 其他變更

此外,此版本還包含以下核心層面的重要變更:

  • 圖片橫幅支持移除:為了定義自定義橫幅,僅考慮 banner.txt 文件有效。
  • 日誌日期格式化器:Logback 和 Log4J2 的新默認日期格式為 yyyy-MM-dd’T’HH:mm:ss.SSSXXX
    如果需要恢復舊默認格式,則需要將 logging.pattern.dateformat 屬性在 application.yaml 中設置為舊值。
  • @ConstructorBinding 僅限於構造函數級別:對於 @ConfigurationProperties 類,不再需要在類型級別使用 @ConstructorBinding ,應移除。
    但是,如果一個類或記錄具有多個構造函數,則必須在所需構造函數上使用 @ConstructorBinding 以指定將用於屬性綁定的構造函數。

3. Web 應用程序變更

最初,假設我們的應用程序是一個 Web 應用程序,我們應該考慮某些變更。

3.1. 後綴斜槓匹配配置

新版本的 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. 響應頭大小

正如我們已經提到的,屬性 <em >server.max.http.header.size</em> 已被棄用,取而代之的是 <em >server.max-http-request-header-size</em>,它僅檢查請求頭的大小。為了同時定義響應頭的大小限制,我們將定義一個新的 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</em/> 和 /configprops</em/> 的值,這些值會顯示敏感信息,例如配置屬性和環境變量。 在本版本中,Spring 改變了方法以更安全地默認進行。

相比之下,現在默認情況下會屏蔽所有鍵的值,而不僅僅是某些鍵。 </strong/>我們可以通過設置以下屬性來更改此配置: management.endpoint.env.show-values</em/> (用於 /env</em/> 端點) 或 management.endpoint.configprops.show-values</em/> (用於 /configprops</em/> 端點),並設置以下值:

  1. NEVER:不顯示任何值
  2. ALWAYS:顯示所有值
  3. WHEN_AUTHORIZED:如果用户已授權,則顯示所有值。 對於 JMX,所有用户都已授權。 對於 HTTP,只能特定角色訪問數據。

4.2. 其他變更

Spring Actuator 模塊上發生了一些相關更新:

  • JMX 端點暴露: JMX 僅處理健康端點。通過配置屬性 <em>management.endpoints.jmx.exposure.include</em><em>management.endpoints.jmx.exposure.exclude</em>,我們可以自定義它。
  • /httptrace” 端點重命名為 “/httpexchanges”。
  • 隔離的 ObjectMapper:此版本現在隔離了負責序列化 Actuator 端點響應的 ObjectMapper 實例。可以通過將 <em>management.endpoints.jackson.isolated-object-mapper</em> 屬性設置為 <em>false</em> 來更改此功能。

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 boot 不再支持位於 spring.security.saml2.relyingparty.registration.{id}.identity-provider 下的屬性。 相反,我們應該使用位於 spring.security.saml2.relyingparty.registration.{id}.asserting-party 下的新屬性。

6. Spring Batch

現在讓我們看看 Spring Batch 模塊中引入的一些重要變更。

6.1. 禁用 <em @EnableBatchProcessing@ 自動配置

此前,我們可以通過在配置類上使用 <em @EnableBatchProcessing@>@EnableBatchProcessing 來啓用 Spring Batch 的自動配置。 新版本的 Spring Boot 建議在希望使用自動配置時禁用此註解。

實際上,使用此註解(或定義實現 DefaultBatchConfiguration 的 Bean)會告知自動配置退避。

6.2. 並行運行多個任務

之前,使用 Spring Batch 可以同時運行多個批處理任務。但現在這種情況不再支持。 如果自動配置檢測到只有一個任務,則應用程序啓動時會自動執行該任務。

因此,如果上下文中存在多個任務,則需要通過提供任務名稱來指定啓動時執行的任務,具體方法是使用 spring.batch.job.name 屬性。 這樣,如果我們想要運行多個任務,則必須為每個任務創建一個單獨的應用程序。

或者,我們可以使用像 Quartz、Spring Scheduler 這樣的調度器來安排任務的執行。

7. HttpClient 變更

Spring Boot 3 升級了其內部 HTTP 棧,使用 Apache HttpClient 5.x 而不是舊版本的 4.x。 因此,那些通過 RestTemplateHttpComponentsClientHttpRequestFactory 定製 HTTP 客户端的應用,需要更新其配置。

此過渡引入了對一些常用模式的破壞性變更,並帶來了更現代的 API 設計,尤其是在 HttpClient 5.4 及更高版本中,它採用基於構建器配置,並與 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 後,這種方法由於與 Apache HttpClient 5 不兼容而失效。

7.2. Spring Boot 3 中導致的問題原因

自定義基於 Apache HttpClient 4.x 的 HTTP 配置不再與 Spring Boot 3 兼容,後者現在依賴 HttpClient 5.x。此升級引入了破壞性 API 變更以及重新組織的包層次結構。

以下是一些關鍵的不兼容之處:

  • HttpComponentsClientHttpRequestFactory 現在期望一個 5.x 的 CloseableHttpClient,而不是 4.x 版本。
  • 超時方法,如 setConnectTimeout()setReadTimeout(),已被棄用或在運行時靜默忽略。
  • 運行時問題,例如 NoSuchMethodErrorClassNotFoundException 或與 org.apache.http.* 類不兼容的情況。

這些問題是由於底層 API 被重新設計,而不是僅僅進行重構造成的。例如,大多數類已從 org.apache.http. 命名空間(在 4.x 中使用)移動到 5.x 中的 org.apache.hc.。配置模型也已轉向 Builder 模式和核心 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));
    }
}
<div>
  <div>
    <p>此外,我們還需要更新 <a href="https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5">HttpClient 依賴項</a>,以包含正確的 Artifact:</p>
  </div>
</div>
<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
</dependency>
<div>
  <div>
    <h1>Introduction</h1>
    <p>This document provides an overview of the new API. It covers key features, usage examples, and troubleshooting tips.</p>
    <h2>Getting Started</h2>
    <h3>Installation</h3>
    <pre><code>npm install my-api-library</code></pre>
    <p>This command installs the necessary dependencies.</p>
    <h3>Basic Usage</h3>
    <pre><code>const myApi = require('my-api-library');

    myApi.doSomething('hello');
    </code></pre>
    <p>This is a simple example of how to use the API.</p>
  </div>
</div>

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 {
            // Timeout configurations
            SocketConfig socketConfig = SocketConfig.custom()
              .setSoTimeout(Timeout.ofSeconds(30))  // Read timeout
              .build();

            ConnectionConfig connectionConfig = ConnectionConfig.custom()
              .setConnectTimeout(Timeout.ofSeconds(30))  // Connect timeout
              .build();

            RequestConfig requestConfig = RequestConfig.custom()
              .setConnectionRequestTimeout(Timeout.ofSeconds(30))  // Pool wait timeout
              .build();

            // Connection pool configuration
            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);
        }
    }
}
<div>
 <p>這種新的方法引入了幾個關鍵的轉變:</p>
 <ul>
  <li><em>超時設置</em>:超時設置使用 <em>Timeout</em> API 在 <em>SocketConfig</em>、<em>ConnectionConfig</em> 和 <em>RequestConfig</em> 中進行,取代了舊的 setter 方法。</li>
  <li><em>連接池</em>: 偏向於使用 builder 模式通過 <em>PoolingHttpClientConnectionManagerBuilder</em>,而不是直接使用 <em>PoolingHttpClientConnectionManager</em>。</li>
  <li><em>基於 Builder 的配置</em>: 整體 API 設計更符合現代 Java 的理念,鼓勵分而治之,並提高可擴展性。</li>
 </ul>
</div>
<p>通過遷移到這種更新的配置模型,我們的應用程序完全兼容 Spring Boot 3,並受益於 HttpClient 5.4 及更高版本中引入的改進的模塊化、清晰度和安全性功能。</p>

8. 結論

在本文中,我們學習瞭如何將 2.7 Spring Boot 應用遷移到 3.0 版本,重點關注 Spring 環境的核心組件。此外,Spring Session、Micrometer 和依賴管理等其他模塊也發生了變化。 有關遷移指南的更多信息,請參考 GitHub 上的文檔。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.