Spring5之WebClient简单使用

2020-11-02  本文已影响0人  因你而在_caiyq

原创文章,转载请注明原文章地址,谢谢!

Spring3.0引入了RestTemplate,但是在后来的官方源码中介绍,RestTemplate有可能在未来的版本中被弃用,所谓替代RestTemplate,在Spring5中引入了WebClient作为非阻塞式Reactive Http客户端。

传统阻塞IO模型

采用阻塞IO模式获取输入数据。每个连接都需要独立的线程,完成数据输入、业务处理、返回。传统阻塞IO模型的问题是,当并发数很大时,就要创建大量线程,占用很大的系统资源。连接创建后,如果当前线程暂时没有数据可读,该线程会阻塞在read操作,造成线程资源浪费。

阻塞IO模型图

响应式IO模型

SpringMVC或Struct等框架都是基于Servlet的,其底层IO模型是阻塞IO模型。Spring社区为了解决SpringMVC的阻塞模型在高并发场景下的性能瓶颈,推出了Spring WebFlux,WebFlux底层实现是久经考验的Netty非阻塞IO通信框架。其实WebClient处理单个HTTP请求的响应时长并不比RestTemplate更快,但是它处理并发的能力更强。 所以响应式非阻塞IO模型的核心意义在于,提高了单位时间内有限资源下的服务请求的并发处理能力,而不是缩短了单个服务请求的响应时长。

Netty的请求处理与线程交互的关系图
与RestTemplate相比,WebClient的优势

WebFlux使用

maven依赖
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
WebClient实例创建
@Test
public void testCreate() {
    Mono<String> mono = WebClient
            //创建WenClient实例
            .create()
            //方法调用,WebClient中提供了多种方法
            .method(HttpMethod.GET)
            //请求url
            .uri("http://localhost:8080/hello")
            //获取响应结果
            .retrieve()
            //将结果转换为指定类型
            .bodyToMono(String.class);
    //block方法返回最终调用结果,block方法是阻塞的
    System.out.println("响应结果:" + mono.block());
}
@Test
public void testCreateBaseUrl() {
    Mono<String> mono = WebClient
            //创建WenClient实例,指定基础url,所以下面uri请求的路径都是基于这个路径
            .create("http://localhost:8080")
            //方法调用,WebClient中提供了多种方法
            .method(HttpMethod.GET)
            //请求url
            .uri("/hello")
            //获取响应结果
            .retrieve()
            //将结果转换为指定类型
            .bodyToMono(String.class);
    //block方法返回最终调用结果,block方法是阻塞的
    System.out.println("响应结果:" + mono.block());
}
@Test
public void testBuilder() {
    Mono<String> mono = WebClient
            .builder()
            //配置头信息,或者其他信息
            .defaultHeader("token", "123456789")
            //创建WebClient实例
            .build()
            //方法调用,WebClient中提供了多种方法
            .method(HttpMethod.GET)
            //请求url
            .uri("http://localhost:8080/hello")
            //获取响应结果
            .retrieve()
            //将结果转换为指定类型
            .bodyToMono(String.class);
}
支持的可选配置

uriBuilderFactory:自定义UriBuilderFactory灵活配置使用Url
defaultHeader:为HTTP请求设置Headers请求头
defaultCookie:为HTTP请求设置Cookies
defaultRequest:自定义HttpRequest
filter:为HTTP请求增加客户端过滤器
exchangeStrategies:HTTP读写信息自定义
clientConnector:HTTP客户端连接器设置

获取响应结果的方式

block()阻塞式获取响应结果
@Test
public void testMono() {
    Mono<User> userMono = WebClient
            .create()
            .method(HttpMethod.GET)
            .uri("http://localhost:8080/hello")
            .retrieve()
            .bodyToMono(User.class);
    User user = userMono.block();
}

@Test
public void testFlux() {
    Flux<User> userFlux = WebClient
            .create()
            .method(HttpMethod.GET)
            .uri("http://localhost:8080/hello")
            .retrieve()
            .bodyToFlux(User.class);
    List<User> users = userFlux.collectList().block();
}

使用Mono和Flux接收返回结果,一个Mono对象包含0个或1个元素,而一个Flux对象包含1个或多个元素。

subscribe()非阻塞式获取响应结果
@Test
public void testSubscribe() {
    Mono<String> mono = WebClient
            .create()
            .method(HttpMethod.GET)
            .uri("http://localhost:8080/hello")
            .retrieve()
            .bodyToMono(String.class);
    mono.subscribe(WebClientTest::handleMonoResp);
}
//响应回调
private static void handleMonoResp(String monoResp) {
    System.out.println("请求结果为:" + monoResp);
}
exchange()获取HTTP响应完整内容
@Test
public void testExchange() {
    Mono<ClientResponse> clientResponseMono = WebClient
            .create()
            .method(HttpMethod.GET)
            .uri("http://localhost:8080/hello")
            .exchange();
    ClientResponse clientResponse = clientResponseMono.block();
    //响应头
    ClientResponse.Headers headers = clientResponse.headers();
    //响应状态
    HttpStatus httpStatus = clientResponse.statusCode();
    //响应状态码
    int rawStatusCode = clientResponse.rawStatusCode();
    //响应体
    Mono<String> mono = clientResponse.bodyToMono(String.class);
    String body = mono.block();
}

占位符传参

数字占位符
public static void main(String[] args) throws Exception {
    List<String> list = new ArrayList<>();
    list.add("a");
    list.add("b");
    String url = "http://localhost:8080/user/{1}/{2}";
    Mono<String> mono = WebClient.create()
            .method(HttpMethod.POST)
            .uri(url, list.toArray())
            .retrieve()
            .bodyToMono(String.class);
    String result = mono.block();
}
参数名占位符
public static void main(String[] args) throws Exception {
    String url = "http://localhost:8080/user/{id}/{name}";
    String id = "123";
    String name = "Boss";
    Mono<String> mono = WebClient.create()
            .method(HttpMethod.POST)
            .uri(url, id, name)
            .retrieve()
            .bodyToMono(String.class);
    String result = mono.block();
}
map传参
public static void main(String[] args) throws Exception {
    String url = "http://localhost:8080/user/{id}/{name}";
    Map<String, String> params = new HashMap<>();
    params.put("id", "123");
    params.put("name", "Boss");
    Mono<String> mono = WebClient.create()
            .method(HttpMethod.POST)
            .uri(url, params)
            .retrieve()
            .bodyToMono(String.class);
    String result = mono.block();
}

博客内容仅供自已学习以及学习过程的记录,如有侵权,请联系我删除,谢谢!

上一篇 下一篇

猜你喜欢

热点阅读