精讲响应式webclient第1篇-响应式非阻塞IO与基础用法

笔者在以前已经写了一系列的关于RestTemplate的文章,以下:html

RestTemplate做为spring-web项目的一部分,在Spring 3.0版本开始被引入。根据Spring官方文档及源码中的介绍,RestTemplate在未来的版本中它可能会被弃用, 做为替代,Spring官方已在Spring 5中引入了WebClient做为非阻塞式Reactive HTTP客户端。
RestTemplate在未来的版本中它可能会被弃用vue

1、什么是响应式非阻塞IO

在开始为你们介绍webClient以前有必要为你们介绍一下响应式非阻塞IO与传统IO以前的区别。咱们先留下一个问题:webClient发送与接收单个HTTP请求比RestTemplate更快么?答案是否认的。 看到这里有的同窗已经蒙了,既然webClient没有更快,那官方为何还推荐使用它?听我往下讲。java

1.1.传统阻塞式IO模型

笔者用相对通俗的话为你们说明一下阻塞IO与非阻塞IO之间的区别。咱们以软件开发团队的工做方式来作一个比喻。做为软件开发人员,咱们确定知道软件开发的基本流程:web

  • 项目立项与可行性研究
  • 需求分析与设计
  • 代码开发
  • 迭代测试
  • 上线及配置管理、运维

在以Spring MVC或者struct为表明的框架都是基于sevlet的,其底层IO模型是阻塞IO模型。这种模型就好像你是公司的一个开发人员,上面的全部的5项工做全都由你一我的完成。若是公司有10我的,最多就只能同时进行10个需求。客户需求增多了也没有办法,只能让他们等着。以下图:一个请求占用一个线程,当线程池内的线程都被占用后新来的请求就只能等待。spring

1.2.响应式IO模型

spring 社区为了解决Spring MVC的阻塞模型在高并发场景下的性能瓶颈的问题,推出了Spring WebFlux,WebFlux底层实现是久经考验的netty非阻塞IO通讯框架。该框架的请求处理与线程交互关系图以下:

boosGroup用于Accetpt链接创建事件并分发请求, workerGroup用于处理I/O读写事件。netty我就不细说了,仍是用通俗的方式给你们讲一下:若是通俗的将上图中的各个任务池、线程池的组合比作一个软件开发公司,那么:编程

  • 项目立项及可研,由公司项目经理及顾问来完成
  • 需求分析与设计,由产品经理和架构师来完成
  • 代码研发,由项目经理带领开发人员来完成
  • 迭代测试,由测试团队来完成
  • 上线及配置管理、运维,可能由专门的devops团队来完成

这样一个公司内的全部人完成分工,就能在有限的资源的状况下,去接触更多的客户,谈更多的需求,合理的分配人力资源,达到并发处理能力最大化的极限水平。相比于一个员工从头到位的负责一个项目,它的组织性更强,分工更明确,合理的利用空闲资源,专业的人最专业的事。
这种人力资源的合理利用及组织方式和非阻塞IO模型有殊途同归之处,经过合理的将请求处理线程及任务进行分类,合理的利用系统的内存、CPU资源,达到单位时间内处理能力的最大化就是异步非阻塞IO的核心用意! 回到上文给你们留下的问题,webClient处理单个HTTP请求的响应时长并不比RestTemplate更快,可是它处理并发的能力更强。因此响应式非阻塞IO模型的核心意义在于:提升了单位时间内有限资源下的服务请求的并发处理能力,而不是缩短了单个服务请求的响应时长。json

2、WebClient 的优点

上文为你们介绍完IO模型以后,我想你们已经能够明白了。与RestTemplate相比,WebClient优点以下:后端

  • 非阻塞响应式IO,单位时间内有限资源下支持更高的并发量
  • 支持使用Java 8 lambda表达式函数
  • 同时支持同步、异步与Streaming流式传输场景

3、项目引入WebClient

使用WebClient须要引入以下的Jar(能够在包含spring-boot-starter-web的Spring Boot项目中引入)springboot

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

那么问题又来了,熟悉Spring 开发的朋友应该都知道。spring-boot-starter-webflux和spring-boot-starter-web表明的是两套技术栈cookie

  • spring-boot-starter-web能够实现目前比较成熟的基于servlet技术栈的Spring Boot应用
  • spring-boot-starter-webflux能够实现的是底层基于netty的响应式编程的技术栈的Spring Boot应用

两者能够共存么?答案是:

  • 做为服务端实现Spring Boot应用而言,两者在应用角度固然是不能共存的。截止20200820我写稿的时间,若是在一个项目里面将两者都引入了,开发服务端应用其实使用的仍是spring-boot-starter-web的基于servlet的技术栈。
  • 做为HTTP客户端而言,若是咱们只是要使用WebClient。不管怎样,引入spring-boot-starter-webflux就对了。

4、WebClient 实例建立与基础用法

建立WebClient有以下三种方式,咱们来一一为你们介绍。

  • WebClient.create()
  • WebClient.create(String baseUrl):指定了baseUrl,使用该客户端发送请求都基于baseUrl
  • WebClient.builder()返回一个WebClient.Builder,该对象能够作链式调用,传递更多的参数。
为了方便后续开发测试,首先介绍一个网站给你们。 JSONPlaceholder是一个提供免费的在线REST API的网站,咱们在开发时可使用它提供的url地址测试下网络请求以及请求参数。或者当咱们程序须要获取一些模拟数据、模拟图片时也可使用它。

4.1. WebClient.create()

建立WebClient发送GET请求,接收String类型单个Mono对象(Mono英文:单声道、单体)。

public class SimpleTest {

  @Test
  void testSimple()  {
    WebClient webClient = WebClient.create();

    Mono<String> mono = webClient
            .get() // 发送GET 请求
            .uri("http://jsonplaceholder.typicode.com/posts/1")  // 请求路径
            .retrieve()    // 获取响应结果
            .bodyToMono(String.class); //响应数据类型转换

    System.out.println("=====" + mono.block());  
  }
}

mono.block()方法仍然是阻塞式的数据响应接收方式,响应式的编程方法咱们后面文章会为你们介绍。

4.2.WebClient.create(String baseUrl)

上面使用create()无参方法,在指定请求uri时每次都要指定完整的HTTP服务路径,如"http://jsonplaceholder.typicode.com/posts/1"。使用WebClient.create(String baseUrl)能够统一指定一个baseUrl,这样请求指定请求uri时,能够省略baseUrl部分,如"/posts/1"。

private WebClient webClient = WebClient.create("http://jsonplaceholder.typicode.com");

@Test
void testBaseUrl(){

  Mono<String> mono = webClient
          .get()
          .uri("/posts/1")  // 请求路径,注意省略了baseurl部分
          .retrieve()
          .bodyToMono(String.class);

  System.out.println("=====" + mono.block());
}

上面代码请求结果,和4.1结果是同样的

4.3.WebClient.builder()

使用builder()建立WebClient对象,能够一次性传递的参数内容就更加丰富了。cookies、headers等信息均可以使用builder来传递。
场景:好比你请求的服务端使用JWT token,每次请求都须要传递token。若是每次请求都单独去建立一个WebClient,而后指定Token,那就麻烦了。咱们可使用builder在WebClient实例化的时候,统一设置Token。

private WebClient webClient = WebClient
        .builder()
        .defaultHeader("JWT-Token", "xxxyyy3fsfsfsff-fjdskfa")
        .build();

支持的可选配置以下:

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

欢迎关注个人博客,里面有不少精品合集

  • 本文转载注明出处(必须带链接,不能只转文字):字母哥博客

以为对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创做动力! 。另外,笔者最近一段时间输出了以下的精品内容,期待您的关注。

相关文章
相关标签/搜索