Spring 中 HTTP 客戶端的現狀

工程 | Brian Clozel | 2025年9月30日 | ...

這是 Road to GA 系列 中的一篇新部落格文章,這次探討了我們 HTTP 客戶端的新功能。這也是反思 Spring 中 HTTP 客戶端狀態的好時機,所以我們將藉此機會解釋一個重要公告:我們正式棄用 RestTemplate

即將推出的 RestClient 功能

RestClient 已在 Spring Framework 6.1 中引入,並在 6.x 系列中不斷發展。在即將釋出的 7.0 主要版本中,我們將透過一系列新功能保持這種發展速度。

API 版本控制

Spring @Controller 現在支援 API 版本控制概念,以在單個應用程式中更好地實現不同代的 REST API。此功能也受客戶端支援,透過使用 ApiVersionInserter。例如,您可以在自定義 HTTP 請求頭中插入 API 版本資訊。這可以在構建客戶端時進行配置。

RestClient customClient = RestClient.builder()
  .baseUrl("https://springframework.tw/api")
  .defaultVersion("1.2")
  .apiVersionInserter(ApiVersionInserter.fromHeader("API-Version").build())
  .build();

Spring 支援從 HTTP 頭、媒體型別、請求路徑、查詢引數或任何自定義實現中插入和解析 API 版本。

HttpMessageConverters

我們重新審視了 Spring 應用程式中訊息轉換器的配置方式。HttpMessageConverters 帶來了一個專用的 API,大大簡化了替換現有轉換器或新增自定義轉換器的自定義安排。在這裡,我們將從類路徑中自動檢測訊息轉換器,並僅使用自定義 Jackson JsonMapper 覆蓋 JSON 支援的轉換器。

JsonMapper jsonMapper = JsonMapper.builder()
  .findAndAddModules()
  .enable(SerializationFeature.INDENT_OUTPUT)
  .defaultDateFormat(new SimpleDateFormat("yyyy-MM-dd"))
  .build();

RestClient restClient = RestClient.builder()
  .configureMessageConverters(client -> {
    client.registerDefaults().jsonMessageConverter(new JacksonJsonHttpMessageConverter(jsonMapper));
  })
  .baseUrl("https://springframework.tw/api")
  .build();

Spring Boot 之前透過其自己的 HttpMessageConverters 型別來滿足這一需求;新的 Framework 變體旨在在 Spring Boot 應用程式中取代它。在 WebFlux 方面,Spring Framework 已經為編解碼器提供了響應式等效項 CodecConfigurer

Http 介面組

當應用程式需要配置許多 Http 介面客戶端時,它們的設定可能會非常重複且難以組織。這個新版本引入了組的概念:一種強大的方式,可以一次宣告和配置許多客戶端,並在有意義時讓它們共享相同的 RestClient

在這裡,我們定義了一個“stackexchange”組,用於查詢 StackOverflow 和 ServerFault API。另一個組“github”將為同一基本包中定義的所有介面共享相同的 HTTP 客戶端。

@Configuration
@ImportHttpServices(group = "stackexchange", types = {StackOverflowClient.class, ServerFaultClient.class})
@ImportHttpServices(group = "github", basePackageClasses = GitHubProjects.class)
public class ClientConfig {

}

您可以在 “HTTP 服務客戶端增強”部落格文章中瞭解有關此功能的更多資訊。

RestTestClient

Spring Framework 7.0 將釋出 RestTestClient,這是一個用於測試伺服器應用程式的新客戶端。RestTestClient 可以對即時伺服器執行整合測試,這意味著它們會測試整個網路堆疊和訊息轉換。RestTestClient 還可以像 MockMvc 一樣,使用模擬請求和響應測試單個控制器或路由器函式。即時伺服器測試和基於模擬的測試都使用相同的 API 來執行交換和斷言。

這是社群的一個熱門請求,因為 WebTestClient 在響應式堆疊中填補了這一空白,但沒有 RestClient 變體。

這個新功能比 Spring Boot 的 TestRestTemplate 帶來了更多價值,可以被視為替代品,這就是 團隊正在考慮棄用它的原因。

新的 Spring Boot Starter

社群多次提出關於 HTTP 客戶端在 Spring 工件中打包方式的擔憂。RestClientRestTemplate 位於“org.springframework:spring-web”中,而 WebClient 位於“org.springframework:spring-webflux”中。這些都沒有單獨的專用客戶端工件。

這種打包結構使得 Spring Boot 更難理解開發人員的意圖。應用程式應該啟動 Web 伺服器、自動配置 HTTP 客戶端,還是兩者兼而有之?這個問題現在透過即將釋出的 Spring Boot 版本中的一個主要功能得到解決:整個 Spring Boot 程式碼庫已經模組化,並且自動配置被拆分為單獨的工件

藉助 Spring Boot 4.0,應用程式現在可以使用“org.springframework.boot:spring-boot-starter-webclient”或“org.springframework.boot:spring-boot-starter-restclient”來表達對 HTTP 客戶端的需求。

更多!

我們還進行了許多其他較小的改進,例如內建緩衝支援客戶端 Jackson 提示支援或Http 介面客戶端的 Spring Security 支援

RestTemplate 的侷限性

如果您的應用程式正在使用 RestTemplate,您很快就會注意到上面提到的大多數新功能不適用於 RestTemplate。在本節中,我們將解釋為什麼我們無法為 RestTemplate 實現這些功能。

RestTemplate 是在 15 多年前的 Spring Framework 3.0 中釋出的,自那以後 Java 生態系統發生了許多變化。

多年來,我們開發 RestTemplate 和所有其他 Spring HTTP 客戶端的動機始終如一:為社群提供一個與 Spring 庫良好整合的高階 HTTP 客戶端。訊息體轉換、錯誤處理、攔截機制和安全性都是您可以使用熟悉的 Spring 程式設計模型使用的功能。我們支援許多 HTTP 客戶端庫,但我們不暴露低階 HTTP 互動或特定配置:您可以選擇適合您需求的那個,但這不應改變整體開發體驗。

這種方法多年來對 RestTemplate 來說運作良好,但我們發現這種模型存在一些侷限性。

“模板式”API 在有限範圍內工作良好,但在新增新功能時可能會面臨挑戰。這是 Spring Framework 中的一個常見模式,始於 JdbcTemplateJmsTemplate,它們早於 HTTP 客戶端。使用這種模式,當範圍擴大時,方法名稱空間會很快變得擁擠,並且使用方法過載來實現變體增加了問題。RestTemplate 的 Javadoc 顯示了許多過載方法,IDE 自動補全也一樣。任何時候引入新功能,開發人員體驗都可能會受到影響。例如,現在在 RestTemplate 中引入 API 版本控制支援將需要新的建構函式並增加 Java API 的混亂。因此,我們無法為 RestTemplate 提供此功能。

使用 AsyncRestTemplate 變體支援非同步呼叫,但這種方法也存在一些問題。由於“模板式”API,方法過載在那裡是一個更大的問題。Spring 的 ListenableFuture 在當時是一個必要的選擇,但我們受限於其組合併發呼叫和高效管理底層 HTTP 資源的能力。當然,如今 Java 平臺提供了更好的替代方案。

流式 HTTP 協議,如“伺服器傳送事件”,也越來越受歡迎。對於 RestTemplate 來說,這種用例更具挑戰性,因為典型的方法是一次性接收和轉換整個響應,然後關閉它;而流式處理需要保持響應在整個流期間處於活動狀態,並逐項執行訊息轉換。

雖然 RestTemplate 存在侷限性,但在 Spring 社群中非常受歡迎。不幸的是,模板式 API 達到了其極限,需要徹底改革。Spring 團隊有機會在 Spring Framework 5 中解決這個問題,並推出了一個名為 WebClient 的新 HTTP 客戶端。

WebClient 和響應式空間

在維護 Spring Framework 4.x 時,我們聽到了 Java 和 Spring 社群中很大一部分人的呼聲:對支援保持低延遲的非同步、非阻塞 Web 堆疊的需求日益增長。新的 Web 框架出現了,其中許多使用函數語言程式設計來組合非同步操作。響應式流成為了行業標準,RSocket 等協議也應運而生。儘管存在學習曲線,許多團隊選擇這種方法來克服傳統 Java 非同步原語和執行緒池的侷限性。

在 Spring Framework 5.0 中,Spring 團隊引入了一個基於 Reactive Streams 和 Reactor 的完整響應式堆疊。從一開始,我們就明確表示傳統的 Servlet 堆疊不會消失,並且團隊只有在面臨嚴重的執行時挑戰時才應考慮這種方法。管理延遲和組合非同步操作是關鍵,而最佳效能從來都不是主要目標。

在 HTTP 客戶端方面,這對團隊來說是一個機會,可以重新審視之前的決策並應用我們從過去中學到的經驗。

我們沒有選擇“模板式”API,而是為我們的新 HTTP 客戶端 WebClient 選擇了一種流式 API。這是新系列流式客戶端中的第一個,之後是 JdbcClientJmsClient。流式 API 顯著減少了任何給定型別的方法數量。IDE 中的自動補全體驗更加集中,因為流式鏈中的每個方法只反映了該點的可用選項,而不是一次性呈現所有可能的選項。

非同步、非阻塞基礎設施是 Reactor 的內建功能。流資料也是響應式流中的一個自然概念。但是流式請求和響應改變了訊息轉換層面的動態。我們不再將資料流作為一個整體來考慮,而是需要將資料解析和寫入為位元組緩衝區。這還與 DataBuffer 契約(而不是 byte[])相結合,可以池化和重用緩衝區以提高記憶體效率。

然後 WebClient 作為一個很好的 RestTemplate 替代品出現了。擴充套件點和 API 風格都很現代。如果高併發或流式 HTTP 呼叫是應用程式的重要功能,WebClient 是一個可行的解決方案。我們不期望僅僅因為這個原因就將整個應用程式用 WebFlux 重寫。這就是為什麼我們確保 Spring MVC 控制器會自然處理響應式型別作為傳統的非同步呼叫。當然,如果需要,應用程式也可以呼叫 block() 返回到同步世界。

那時,我們宣佈 RestTemplate 為“功能完整”:由於其侷限性,我們無法在那裡承諾新功能。鑑於 WebClient 在此類需求方面的優越性,我們當時棄用了 AsyncRestTemplate:其非同步和非阻塞支援,以及組合操作和流式管道的能力遠超其前。總的來說,WebClient 是一個更好的全能替代品,當時我們希望社群最終能收斂於一個單一的解決方案。

引入 RestClient

隨著 Spring Framework 6.0 中新的 Java 17 基線和 Java 21 中計劃支援虛擬執行緒,我們看到了重新審視 RestTemplate 的機會。我們利用從 WebClient 中學到的經驗,透過現代、流式 API 解決了“模板式”的侷限性。我們選擇重用 RestTemplate 現有的 HTTP 基礎設施,並將這個新客戶端放在同一個包中。這使得遷移更加容易,因為您可以使用現有的 RestTemplate 建立 RestClient 例項。我們還發布了專門的遷移指南,以幫助開發人員完成該過程。

回想起來,選擇保持命令式、阻塞式 API 是一個很好的選擇:結構化併發RestClient 解鎖了非同步組合,而無需額外的更改。我們仍然不確定流式用例(稍後會詳細介紹)。

在最近幾個版本中,我們看到了社群對 RestClient 的快速採用,但直到現在,我們還沒有重新審視我們對 RestTemplate 的維護立場。

Spring 中 HTTP 客戶端的未來

到目前為止,RestTemplateRestClient 之間存在顯著差距,由於模板式 API 的限制,我們無法彌合。保留 RestTemplate 會使我們社群的一部分處於劣勢。我們現在認為是時候重新考慮我們的 HTTP 客戶端安排了,這是我們當前的計劃。

  1. Spring Framework 7.0(2025 年 11 月):在此部落格文章、我們的升級指南和參考文件中宣佈我們棄用 RestTemplate 的意圖。
  2. Spring Framework 7.1(暫定日期,2026 年 11 月):正式“@Deprecate”該客戶端並標記為移除。
  3. Spring Framework 8.0(日期待定):完全移除 RestTemplate

假設我們目前的釋出速度,RestTemplate 的開源支援將至少持續到 2029 年。我們堅信,更新應用程式以使用 RestClient(和相同的底層基礎設施)是最佳的長期解決方案。如果您的團隊維護自定義請求工廠或客戶端攔截器,這些都可以與 RestClient 重用。應用程式可以迭代升級,最初將現有的 RestTemplate 例項包裝在 RestClient 中,然後重構共享配置。

這種新安排使我們擁有用於傳統堆疊的 RestClient 和用於響應式變體的 WebClient,兩者都由團隊積極維護。決策過程變得容易得多:在大多數情況下,您可以選擇 RestClient,或者如果您需要響應式 API 或流功能,則選擇 WebClient

現在,回到流式用例。我們仍在探索在 RestClient 中實現適當流式支援的選項。目前 Java 平臺中沒有明確的流式支援路徑,也沒有一個能自然地與虛擬執行緒和結構化併發配合。我們正在與 Java 平臺團隊和更廣泛的行業保持聯絡。

我們即將迎來 Spring Framework 7.0 和 Spring Boot 4.0 的釋出日期。您能否用您的一個應用程式試用最新的里程碑版本?現在仍然是改進升級體驗並讓您在不久的將來工作更輕鬆的時候。一如既往,您的意見很重要——請不要猶豫,在此處評論中分享您使用 Spring HTTP 客戶端的經驗!

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有