還在用OpenFeign?來試試SpringBoot3 中的這個新玩意!

2023.02.03

還在用OpenFeign?來試試SpringBoot3 中的這個新玩意!

用過Spring Cloud 的小伙伴都知道,在Spring Cloud 家族中,負責進程間通信的,我們可以使用RestTemplate 或者OpenFeign(當然也有其他方式如基於消息中間件的消息驅動的微服務或者基於gRPC 的調用等)。

年過完啦,松哥也已經搬磚搬了三天了。

疫情放開後,今年這個年格外的輕鬆愜意,心中一種特別壓抑的東西被除去了,新聞中看到各地遊人如織、西安大唐不夜城遊人摩肩接踵,真的好像回到了2019 年一樣,朋友圈中也都是喜氣洋洋,生活還是很美好的。

好久沒發技術文章了,最近回到工作地,晚上有空又可以碼碼技術了,今天我們就來聊一個Spring Boot3 中的新鮮玩意,聲明式HTTP 調用。

1. 由來

Spring Boot3 去年底就已經正式發布,我也嚐了一把鮮,最近有空會和小伙伴們慢慢聊聊Spring Boot3 都給我們帶來了哪些新東西。

今天我們就先來看看聲明式HTTP 接口。

用過Spring Cloud 的小伙伴都知道,在Spring Cloud 家族中,負責進程間通信的,我們可以使用RestTemplate 或者OpenFeign(當然也有其他方式如基於消息中間件的消息驅動的微服務或者基於gRPC 的調用等)。

RestTemplate 我們可以將之當作一個普普通通的HTTP 調用工具來對待,區別於其他的HTTP 客戶端,RestTemplate 用來調用RESTful 風格的接口特別方便。

不過,比RestTemplate 更加方便的是OpenFeign,通過接口聲明就可以實現遠程調用,這些的具體用法松哥在之前的視頻中講過,這裡就不再贅述了。

以前我們想要用聲明式HTTP 調用,需要通過OpenFeign 來實現,這個需要第三方的依賴,從Spring6 開始(Spring Boot3),Spring 自己提供了類似的功能通過 @HttpExchange 註解也能方便的實現聲明式HTTP 調用。以後跨服務調用又多了一個選擇。

2. 使用

接下來松哥通過一個案例來和小伙伴們演示一下 @HttpExchange 註解的具體玩法。

首先我們先創建一個普通的名為server 的Spring Boot 項目,這個普通的Spring Boot 項目中只需要提供一個簡單的測試接口即可,如下:

@RestController
public class HelloController {

    @GetMapping("/server/hello")
    public String hello(String name){
        return "hello " + name;
    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

這個對大家來說應該是沒什麼難度的,我就不多說了。

現在假設我有另外一個服務名為client,我想在client 中調用server 中提供的這個接口。

首先我们来创建 client 这个项目,大家注意,创建的时候我们不仅需要添加 Web 依赖,还需要 Reactive Web,因为这个 @HttpExchange 底层基于 WebClient,而 WebClient 则是 Reactive Web 提供的:

圖片

创建完成后,接下来我们就可以声明 Http 接口了:

@HttpExchange("/server")
public interface ToDoService {
    @GetExchange("/hello")
    String hello(@RequestParam String name);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

这些用法跟我们在 SpringMVC 中常用的 @RequestMapping 和 @GetMapping 等特别类似:

  • @HttpExchange​ 类似于 @RequestMapping,可以将之放在类上,起到一个请求窄化的作用,也可以放在方法上,放在方法上我们可以通过 method 属性来指定具体的请求方法,这个也跟 @RequestMapping 类似:@HttpExchange(value = "/server",method = "GET")。
  • @GetExchange​ 类似于 @GetMapping,这个就不再赘述了,其他类似的注解还有 @DeleteExchange、@PatchExchange、@PostExchange、@PutExchange 等。
  • 另外需要注意的是请求方法的参数需要加上@RequestParam 注解,这一点和 OpenFeign 比较类似。

接口声明好之后还没完,我们还需要配置一下才能使用。如下:

@Configuration
public class WebConfig {
    @Bean
    WebClient webClient(){
        return WebClient.builder()
                .baseUrl("http://localhost:8080")
                .build();
    }
    @Bean
    ToDoService toDoService(){
        HttpServiceProxyFactory httpServiceProxyFactory =
                HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient()))
                        .build();
        return httpServiceProxyFactory.createClient(ToDoService.class);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

这个配置主要是两方面:

  1. @HttpExchange​ 是基于 WebClient 的,所以我们首先需要配置 WebClient,配置 WebClient 的时候,也顺便配置了请求的具体地址(因为在 @HttpExchange 
  2. 由于我们前面提供的 ToDoService 是一个接口,所以我们还需要提供一个该接口的实现类,当然这个配置完全是套路化模版化的,这块就没啥好说了。

全部配置完成后,接下来我们就可以在任何需要的地方,直接注入 ToDoService 的实例去使用了,举一个简单的例子小伙伴们参考下:

@SpringBootTest
class ClientApplicationTests {

    @Autowired
    ToDoService toDoService;

    @Test
    void contextLoads(){
        String hello = toDoService.hello("javaboy");
        System.out.println("hello = " + hello);
    }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

好啦,一个简单的例子,小伙伴们不妨体验下。

以后,不用 OpenFeign 也能实现声明式服务调用啦~