> ## Documentation Index
> Fetch the complete documentation index at: https://blog.pig4cloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Spring intereface

# Spring 7.0 新特性！彻底告别HTTP客户端配置地狱

## 引言

自 Spring Framework 6 引入 `@HttpExchange` 注解以来，通过 Java 接口定义 HTTP 服务变得前所未有的简单。在AI时代，这一特性显得尤为重要，特别是在调用各种第三方AI算力服务时。

![](https://minio.pigx.vip/oss/202509/eilQRG.png)

如上图所示，PIG AI 充分利用了 HTTP Interface 功能的强大能力，实现了对非标准（非OpenAI）协议接口的完美兼容。通过这种方式，我们不仅满足了 Spring AI 和 LangChain4j 等框架对高级Service概念的要求，还能够复用现有的模型监控体系，让代码结构更加清晰和可维护。例如：

## AI Services 的强大能力

由于 LLM 驱动的应用程序通常不仅需要单个组件，还需要多个组件协同工作（例如，提示模板、聊天记忆、LLM、输出解析器、RAG 组件：嵌入模型和存储）并且经常涉及多次交互，协调所有这些组件变得更加繁琐。

开放人员专注于业务逻辑，而不是低级实现细节。因此 Java AI 目前可以通过 HTTP Interface 的方式，我们可以优雅地将这些 AI 服务封装为标准的 Spring Bean，实现统一的配置和管理。

```java theme={null}
public interface MilestoneService {

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

在客户端，你可以这样生成代理来执行 HTTP 请求：

```java theme={null}
// 初始化 HTTP 客户端
RestClient restClient = RestClient.create("https://api.github.com");

// 创建客户端代理工厂
HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder()
        .exchangeAdapter(RestClientAdapter.create(restClient))
        .build();

// 创建客户端代理
MilestoneService client = proxyFactory.createClient(MilestoneService.class);

// 使用代理执行 HTTP 请求
List<Milestone> milestones = client.getMilestones("spring-projects", "spring-framework");
```

在服务端，`@Controller` 类可以实现相同的接口来处理请求（如果 HTTP 服务是你自己的）。

## 配置开销的痛点

![QSNgdr](https://minio.pigx.vip/oss/202509/QSNgdr.png)

HTTP 服务客户端支持功能强大、表达力强且易于使用。但是，随着客户端代理数量的增长，配置变得重复且繁琐，特别是客户端代理通常需要声明为 Spring beans 时。如上图所示，当需要接入非标准模型（如智谱AI、通义千问等）时，往往需要为每个服务提供商创建单独的 service factory，这进一步加剧了配置的复杂性和重复性。

考虑以下示例：

```java theme={null}
@Bean
MilestoneService milestoneService(HttpServiceProxyFactory factory) {
    return factory.createClient(MilestoneService.class);
}

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

// 更多客户端 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 7 引入了一个额外的注册表层**，覆盖在 `HttpServiceProxyFactory` 之上，提供以下功能：

* **配置模型**：注册 HTTP 接口并初始化 HTTP 客户端基础设施
* **透明创建**：自动创建和注册客户端代理作为 Spring beans
* **统一访问**：通过 `HttpServiceProxyRegistry` 访问所有客户端代理

在配置模型中，HTTP 服务按组组织，其中一个组只是一组共享相同 HTTP 客户端配置和生成的客户端实例的 HTTP 服务。

## 声明式注册

使用 `@ImportHttpServices` 注解（Spring Framework 7 新增）可以声明 HTTP 服务组。

### 手动列出 HTTP 服务

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

### 包扫描检测

```java theme={null}
@ImportHttpServices(group = "github", basePackages = "client.github")
@ImportHttpServices(group = "stackoverflow", basePackages = "client.stackoverflow")
@Configuration
public class DemoConfig {
}
```

HTTP 服务组默认配置为 `RestClient`，但你可以通过注解的 `clientType` 属性切换到 `WebClient`。

## 程序化注册

如果你需要对过滤或其他注册逻辑有更多控制，也可以通过两个步骤以编程方式声明 HTTP 服务。

### 步骤 1：创建注册器

```java theme={null}
public class CustomHttpServiceRegistrar extends AbstractHttpServiceRegistrar { 

    @Override
    protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata metadata) {
        registry.forGroup("github").detectInBasePackages("client.github");
        // 更多注册...
    }
}
```

### 步骤 2：导入注册器

```java theme={null}
@Configuration
@Import(CustomHttpServiceRegistrar.class) 
public class ClientConfig {
}
```

## HTTP 客户端初始化

声明了 HTTP 服务组后，剩下的就是为每个组配置 HTTP 客户端。你可以使用 `HttpServiceGroupConfigurer` bean 方法：

```java theme={null}
@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"));
    };
}
```

## 生态系统集成

### Spring Boot 4.0 集成

Spring Boot 4.0 透明地通过其 `RestClient` 和 `WebClient` 自动配置为每个组应用 HTTP 客户端构建器的初始化。还提供了按组的 HTTP 客户端属性支持：

```properties theme={null}
# 全局配置，适用于所有组
spring.http.client.service.read-timeout=2s

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

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

### 其他集成

* **Spring Cloud 2025.1**：为 HTTP 服务组提供透明的负载均衡和熔断支持
* **Spring Security 7.0**：为检测 `@HttpExchange` 方法上的 `@ClientRegistrationId` 注解的 HTTP 服务组提供 OAuth 支持

## 总结

新的 HTTP 服务注册表让应用程序可以声明 HTTP 服务并配置底层客户端基础设施，而框架完成其余工作。这也是一个可扩展的机制，用于强大的、开箱即用的 HTTP 客户端初始化功能。

### 主要优势

* **简化配置**：告别重复的 bean 声明
* **统一管理**：按组组织 HTTP 服务
* **生态集成**：与 Spring Boot、Spring Cloud、Spring Security 无缝集成
* **灵活配置**：支持声明式和程序化两种方式

Spring 团队知道在这个主题上有很多场景和观点，也有使用 OpenFeign 的长期经验。同时，当我们将功能引入 Spring Framework 时，这是一个以全新视角重新审视它的机会，并提供一些更简单和更广泛有用的东西。

*参考资料：[Spring 官方博客 - HTTP Service Client Enhancements](https://spring.io/blog/2025/09/23/http-service-client-enhancements)*
