HTTP 服務客戶端增強功能

工程 | Rossen Stoyanchev | 2025年9月23日 | ...

Road to GA 系列的第三篇部落格文章中,我們重點介紹了 Spring 組合中針對 將於 11 月釋出的下一個主要版本 的主要功能,我們將探討 HTTP 服務客戶端的新功能,這是多個 Spring 專案的協作成果。

引言

Spring Framework 6 引入了透過帶有 @HttpExchange 註解方法的 Java 介面定義 HTTP 服務的能力。例如

public interface MilestoneService {

    @GetExchange("/repos/{org}/{repo}/milestones")
    List<Milestone> getMilestones(@PathVariable String org, @PathVariable String repo);

}

在客戶端,您可以從介面生成代理,以執行 HTTP 請求,如下所示

// Initialize HTTP client
RestClient restClient = RestClient.create("https://api.github.com");

// Create factory for client proxies
HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder()
        .exchangeAdapter(RestClientAdapter.create(restClient))
        .build();

// Create client proxy
MilestoneService client = proxyFactory.createClient(MilestoneService.class);

// Use proxy for HTTP requests
List<Milestone> milestones = client.getMilestones(“spring-projects”, “spring-framework”);

在伺服器端,如果 HTTP 服務是您的,@Controller 類可以實現相同的介面來處理請求。

HTTP 服務客戶端支援功能強大、表達力強且易於使用。它允許一個團隊掌握 REST API 的工作方式、哪些部分與客戶端應用程式相關、要建立哪些輸入和輸出型別、需要哪些端點方法簽名、需要哪些 Javadoc 等知識。生成的 Java API 可以指導開發人員,並可立即使用。

這些模式長期以來與 Spring Cloud OpenFeign 一起使用,現在已可供所有 Spring Framework 6+ 應用程式與 RestClientRestTemplateWebClient 一起使用。HTTP 服務客戶端支援在 6.x 時間線中經歷了大量由反饋驅動的演變,但一個主要挑戰仍然存在。

配置開銷

建立 HttpServiceProxyFactory 並使用它來建立一兩個或三個客戶端代理是微不足道的,但隨著數量的增長,這變得重複且麻煩,尤其因為客戶端代理通常宣告為 Spring Bean。例如,考慮以下情況:

@Bean
MilestoneService milestoneService(HttpServiceProxyFactory factory) {
    return factory.createClient(MilestoneService.class);
}

@Bean
ReleaseService releaseService(HttpServiceProxyFactory factory) {
    return factory.createClient(ReleaseService.class);
}

// More client beans

@Bean
HttpServiceProxyFactory proxyFactory(RestClient.Builder clientBuilder) {
    RestClient client = clientBuilder.baseUrl("https://api.github.com").build();
    return HttpServiceProxyFactory.builderFor(RestClientAdapter.create(client)).build();
}

REST API 暴露了許多細粒度端點。GitHub API 有數十個,甚至數百個,雖然您肯定不需要所有這些,但根據實際需要,很容易最終得到至少十幾個或更多。

此外,與多個 REST API 整合是很常見的,這意味著更多的介面以及更復雜的底層 HTTP 客戶端配置。

HTTP 服務註冊

為了解決這個挑戰,Spring Framework 7HttpServiceProxyFactory 之上引入了一個額外的註冊層,提供以下功能:

  • 用於註冊 HTTP 介面和初始化 HTTP 客戶端基礎設施的配置模型
  • 透明地建立和註冊客戶端代理作為 Spring Bean
  • 透過 HttpServiceProxyRegistry 訪問所有客戶端代理

在配置模型中,HTTP 服務按組組織,其中組只是一組共享相同 HTTP 客戶端配置和結果客戶端例項的 HTTP 服務。

目前,有兩種宣告 HTTP 服務的方式。

宣告式註冊

宣告 HTTP 服務組的一種方式是透過 @ImportHttpServices 註解(Spring Framework 7 中新增)。

您可以使用它按組手動列出 HTTP 服務

@ImportHttpServices(group = "github", types = {MilestoneService.class, … })
@ImportHttpServices(group = "stackoverflow", types = {QuestionService.class, … })
@Configuration
public class DemoConfig {
}

或者讓它們在基礎包下被檢測到

@ImportHttpServices(group = "github", basePackages = “"client.github")
@ImportHttpServices(group = "stackoverflow", basePackages = “client.stackoverflow”)
@Configuration
public class DemoConfig {
}

HTTP 服務組預設配置為 RestClient,但您可以透過註解的 clientType 屬性切換到 WebClient

程式設計式註冊

如果您需要對過濾或其他註冊邏輯有更多控制,您還可以分兩步以程式設計方式宣告 HTTP 服務。

首先,建立一個宣告 HTTP 服務組的註冊器

public class CustomHttpServiceRegistrar extends AbstractHttpServiceRegistrar { 

    @Override
    protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata metadata) {
        registry.forGroup("github").detectInBasePackages(“client.github);
        // more registrations…
    }
}

然後匯入註冊器

@Configuration
@Import(CustomHttpServiceRegistrar.class) 
public class ClientConfig {
}

請注意,宣告式和程式設計式註冊都依賴於 ImportBeanDefinitionRegistrar,它在 Spring 配置生命週期的早期階段,即 Bean 定義級別介入。這使得客戶端代理 Bean 可用於依賴注入,並有助於避免生命週期問題。

HTTP 客戶端初始化

一旦聲明瞭 HTTP 服務組,剩下的就是為每個組配置 HTTP 客戶端。您可以使用 HttpServiceGroupConfigurer Bean 方法來完成此操作。例如:

@Bean
RestClientHttpServiceGroupConfigurer groupConfigurer() {
    return groups -> {

        groups.filterByName("github").forEachClient((_, builder) ->
                builder.baseUrl("https://api.github.com"));

        groups.filterByName("stackoverflow").forEachClient((_, builder) ->
                builder.baseUrl("https://api.stackexchange.com?site=stackoverflow"));
    };
}

您可以擁有任意數量的 HTTP 服務組配置器,這些配置器可以是應用程式或框架擁有的。

例如,Spring Boot 4.0 透過其 RestClientWebClient 自動配置透明地為每個組應用 HTTP 客戶端構建器的初始化。此外,它還提供了按組配置 HTTP 客戶端屬性的支援

# Global, applies to all groups
spring.http.client.service.read-timeout=2s

# GitHub group
spring.http.client.service.group.github.base-url=https://api.github.com

# Stackoverflow group
spring.http.client.service.group.stackoverflow.base-url=https://api.stackexchange.com

Spring Cloud 2025.1 為 HTTP 服務組提供了負載均衡斷路器的透明支援。

Spring Security 7.0 為 HTTP 服務組提供了 OAuth 支援,它會在 @HttpExchange 方法上檢測 @ClientRegistrationId 註解。與 spring-security#17940 相關的額外身份驗證支援正在考慮中。

總結

新的 HTTP 服務登錄檔允許應用程式宣告 HTTP 服務並配置底層客戶端基礎設施,而框架則負責其餘部分。它還是一個可擴充套件的機制,用於提供功能強大、開箱即用的 HTTP 客戶端初始化功能。

我們知道在這個主題上存在各種各樣的場景和觀點,也有著豐富的 OpenFeign 使用經驗。與此同時,我們將一項功能引入 Spring Framework,這是一個以全新視角重新審視它並提供更精簡和廣泛有用的功能的機會。我們需要您嘗試我們提出的方案,並告訴我們它在您的具體場景中如何工作。

示例

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

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

瞭解更多

獲得支援

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

瞭解更多

即將舉行的活動

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

檢視所有