# Spring Framework 6.0/Spring Boot 3.0新特性：简单的远程调用HTTP Interfaces

在Spring 6.0之前，我们访问第三方服务或者微服务的http接口主要有这些方式：

- RestTemplate：可同步访问HTTP服务。
- WebClient：可同步或异步访问HTTP服务。
- Feign：在微服务架构中（不限于微服务），用声明式的方式访问HTTP服务。
在Spring 6.0中，我们有了一个更方便的HTTP请求的手段，HTTP Interfaces。HTTP Interfaces类似于Spring Data的Repository或者Spring Cloud OpenFeign一样，我们只需要声明接口就可以完成工作，框架会直接给我们自动代理一个实现。

在实际使用中HTTP Interfaces和Spring Cloud OpenFeign使用感受极其类似。

下面我进行一个极其简单的演示。

### 1、创建Spring Boot 3工程
打开https://start.spring.io，Spring Boot版本选择3.0.0（SNAPSHOT）（当前最新版本，若有更新版本选择最新版本），Java版本选择17（Spring Boot最低支持版本），依赖选择Spring Web、Spring Reactive Web、Lombok（此时我们还是常规使用Tomcat的同步调用，添加Spring Reactive Web是为了使用WebClient）。

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663315497594/w5mBUw4T8.png align="left")

### 2、一个在线REST HTTP服务
[https://jsonplaceholder.typicode.com](https://jsonplaceholder.typicode.com)

提供多个REST资源。


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663315534867/-xTpL-tu1.png align="left")


我们可以对这些资源进行增删查改的操作，本例选用todos资源。



### 3、编写客户端和服务端之间的数据传值对象（DTO）

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663315546069/JwpjrMzQT.png align="left")


根据在线资源服务的数据结构编写DTO

```java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Todo {
   private Long id;
   private Long userId;
   private String title;
   private Boolean completed;
}
```
### 4、编写HTTP客户端
```java
@HttpExchange("/todos")
public interface TodoClient {

    @GetExchange("/{todoId}")
    Todo getTodo(@PathVariable Integer todoId);

    @GetExchange
    List<Todo> getTodos();

    @PostExchange
    Todo save(@RequestBody Todo todo);
}
```
这里和Spring WebMVC的用法是很类似的，不过它声明的是远程的资源，和Spring Cloud OpenFeign一样。

- `@HttpExchange`：最通用的一个注解，在类级别将会被所有方法继承，如基础路径地址；在方法级别，需要指定具体的method类型。相当于`@RequestMapping`。
- `@GetExchange`：HTTP GET请求。相当于`@GetMapping`。
- `@PostExchange`：HTTP POST请求。相当于`@PostMapping`。
- `@PutExchange`：HTTP PUT请求。相当于`@PutMapping`。
- `@DeleteExchange`：HTTP DELETE请求。相当于`@DeleteMapping`。
- `@PatchExchange`：HTTP PATCH请求。相当于`@PatchMapping`。
### 5、注册HTTP客户端
```java
@Configuration
public class ClientConfig {
    @Bean
    public TodoClient todoClient() throws Exception {
        WebClient webClient = WebClient.builder()
                .baseUrl("https://jsonplaceholder.typicode.com")
                .build();
        HttpServiceProxyFactory factory = new HttpServiceProxyFactory(WebClientAdapter.forClient(webClient));
        factory.afterPropertiesSet();
        return factory.createClient(TodoClient.class);
    }
}
```
我们的HTTP客户端TodoClient是利用WebClient来实现的。这块以后WebClient应该从Spring Reactive Web剥离出来，或者提供更多其他的HTTP Client的实现，这样就不需要依赖于Spring Reactive Web了。

### 6、演示
```java
@SpringBootApplication
@Slf4j
public class HttpInterfacesApplication {

	public static void main(String[] args) {
		SpringApplication.run(HttpInterfacesApplication.class, args);
	}

	@Bean
	CommandLineRunner clr(TodoClient todoClient){
		return args -> {
			log.info(todoClient.getTodo(1).toString());
			log.info(todoClient.save(new Todo(null, 1L, "看书", false)).toString());
			for(Todo todo : todoClient.getTodos()){
				log.info(todo.toString());
			}
		};
	}

}
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663315631528/ytFCK9pv4.png align="left")
### 结语
HTTP interfaces使用起来比RestTemplate和WebClient要简单很多，使用声明式类似于OpenFeign的方式进行远程的HTTP资源的调用，但不需要额外引用Spring Cloud OpenFeign，极大的简化了代码和提高了开发效率。
