WebFlux 响应式编程初体验

Posted Johnny屋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebFlux 响应式编程初体验相关的知识,希望对你有一定的参考价值。

WebFlux 响应式编程初体验

本篇主要讲解WebFlux 响应式编程,WebFlux的概念,Reactor的Mono Flux ,以及WebFlux的优点和使用场景 WebFlux 是Spring5提供的 基于Reactor 框架(它实现Reactive Streams一种支持背压(Backpressure)的异步数据流处理标准),Spring WebFlux默认集成Reactor

 1.前言

 现在大多数情况下Java开发都在使用SpringMVC来做Web开发,当我们还在不亦乐乎的使用着SpringMVC的时候,Spring又悄悄的推出了Spring WebFlux ,不是已经有了SpringMVC这么好的框架了吗,为什么还要推出这个?

众所周知,SpringMVC是同步阻塞的IO模型,资源浪费相对来说比较严重,当我们在处理一个比较耗时的任务时,比如写文件到磁盘中,这期间容器线程(Tomcat线程)会一直在等待处理完成返回结果才能去接收其他的请求,这不是浪费资源吗?这就是Spring WebFlux 推出的原因!

 2.WebFlux的概念

 先看图:

 左边是传统的SpringMVC模式下的各个组件 ,相对应到WebFlux上的各个组件 从上到下依次是Router Functions,WebFlux,Reactive Streams三个新组件。

Router Functions: 对标@Controller,@RequestMapping等标准的Spring MVC注解,提供一套函数式风格的API  WebFlux: 核心组件,协调上下游各个组件提供响应式编程支持。 Reactive Streams: 一种支持背压(Backpressure)的异步数据流处理标准,主流实现有RxJava和Reactor,Spring WebFlux默认集成的是Reactor。

概念  Spring5提出的新的开发Web的技术栈,非阻塞的开发模式,运行在netty或servlet3.1上,支持很高的并发量

非阻塞的概念:

  1. WebFlux一个线程里可以处理更多的请求

  2. 老的开发模式:一个请求会对应容器里的一个线程

运行环境的不同:

  1. 老的开发模式:基于ServletAPI,即运行在Servlet容器上面

  2. Webflux开发模式:基于响应式流,可以运行在Servlet3.1之后的容器(异步Servlet容器)或Netty上

数据库的不同:

  1. 目前关系型数据库都是不支持响应式(基于JDBC)的数据库

  2. Reactive stack的SpringDataReactiveRepositories是:Mongo,Cassandra,Redis,Couchbase

 3.WebFlux 初体验

  2.1 创建项目

  通过IDEA 创建SpringBoot2.0 项目,记得勾选 Spring Reactive Web 依赖WebFlux 响应式编程初体验

  pom.xml 文件中会自动添加如下依赖

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

WebFlux 响应式编程初体验

  2.2 编写SpringMVC接口

@RequestMapping("/helloSpringMvc")
public String helloSpringMvc() {
log.info("【helloSpringMvc start】");
doSomeThing();
log.info("【helloSpringMvc end】");
return "Hello SpringMVC";
}

private String doSomeThing() {

try {
//模拟耗时操作
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}

return "Hello WebFlux";
}

  启动项目并且在浏览器访问

http://localhost:8080/helloSpringMvc

  看后台可以看出确实等待了5秒钟

WebFlux 响应式编程初体验

  2.3 编写WebFlux 接口

  WebFlux接口需要返回Mono或者Flux 数据,可以看到WefFlux接口还是可以按照以前SpringMVC接口的编写模式 使用@RequestMapping注解,这得益于Spring的强大,主要是方便我们从SpringMVC过度到WebFlux

@RequestMapping("/helloWebFlux")
public Mono<String> helloWebFlux() {
log.info("【helloWebFlux start】");

//这段代码的doSomeThing是在线程池中执行的,不是Web(Tomcat)容器线程,Tomcat容器线程直接返回了
//而这个result Mono是一个发布者,它的订阅者是SpringWebFlux去实现的,当这个发布者在其他线程中执行完毕后得到数据(即产生数据并提交)后
//则SpringWebFlux对应的实现的订阅者 会收到数据,并且把数据放到Http Response 返回给前端

Mono<String> result = Mono.fromSupplier(() -> doSomeThing());

log.info("【helloWebFlux end】");
return result;
}

  启动项目并且在浏览器访问

http://localhost:8080/helloWebFlux

  看后台可以看出线程执行时间只有2毫秒,该线程就已经可以去接收其他请求了

 4.WebFlux Reactor 发射器

 Reactor的主要类: 在Reactor中,经常使用的类并不多,主要有以下两个:

Mono 实现了 org.reactivestreams.Publisher 接口,代表0到1个元素的发布者(Publisher)。 Flux 同样实现了 org.reactivestreams.Publisher 接口,代表0到N个元素的发布者(Subscriber)。

  3.1 Mono

Mono 发射0到1个元素的异步"发射器

@RequestMapping("/hellMono")
public Mono<String> hellMono(){
return Mono.just("Hello Mono");
}

  3.2 Flux

发射0到N个元素的异步"发射器

@RequestMapping("/hellFlux")
public Flux<String> hellFlux(){
return Flux.just("Hello Flux1", "Hello Flux2");
}

  其实了解JDK9 Reactive Stream 响应式流的 一定知道这里的Mono和Flux其实就是对应响应式流中的Publisher,如果不了解可以看我的另一篇博客 JDK9新特性 Reactive Stream 响应式流

  其实,对于大部分业务开发人员来说,当编写反应式代码时,我们通常只会接触到 Publisher 这个接口,对应到 Reactor 便是 Mono 和 Flux。对于 Subscriber 和 Subcription 这两个接口,Reactor 必然也有相应的实现。但是,这些都是 Web Flux 和 Spring Data Reactive 这样的框架用到的。如果不开发中间件,通常开发人员是不会接触到的。

  比如,在 Web Flux,你的方法只需返回 Mono 或 Flux 即可。你的代码基本也只和 Mono 或 Flux 打交道。而 Web Flux 则会实现 Subscriber ,onNext 时将业务开发人员编写的 Mono 或 Flux 转换为 HTTP Response 返回给客户端。

  下面就是模拟实现订阅者,结合Flux的案例

  Subscriber<Integer> subscriber = new Subscriber<>() {

private Subscription subscription;

@Override
public void onSubscribe(Subscription subscription)
{
this.subscription = subscription;
System.out.println("订阅成功。。");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
subscription.request(1);
System.out.println("订阅方法里请求一个数据");
}


@Override
public void onNext(Integer item)
{
log.info("【onNext 接受到数据 item : {}】 ", item);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
subscription.request(1);
}

@Override
public void onError(Throwable throwable)
{
log.info("【onError 出现异常】");
subscription.cancel();
}

@Override
public void onComplete()
{
log.info("【onComplete 所有数据接收完成】");
}
};

//使用Flux 来作为Publisher
String[] strings = {"1","2","3"};

Flux.fromArray(strings).map(s -> Integer.parseInt(s))
.subscribe(subscriber);

 5.WebFlux 的优势&提升性能?

 WebFlux 内部使用的是响应式编程(Reactive Programming),以 Reactor 库为基础, 基于异步和事件驱动,可以让我们在不扩充硬件资源的前提下,提升系统的吞吐量和伸缩性。

看到这里,你是不是以为 WebFlux 能够使程序运行的更快呢?量化一点,比如说我使用 WebFlux 以后,一个接口的请求响应时间是不是就缩短了呢?

抱歉了,答案是否定的!以下是官方原话:

Reactive and non-blocking generally do not make applications run faster.

WebFlux 并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性。

 6.WebFlux 应用场景

 上面说到了, Spring WebFlux 是一个异步非阻塞式的 Web 框架,所以,它特别适合应用在 IO 密集型的服务中,比如微服务网关这样的应用中。

PS: IO 密集型包括:磁盘IO密集型, 网络IO密集型,微服务网关就属于网络 IO 密集型,使用异步非阻塞式编程模型,能够显著地提升网关对下游服务转发的吞吐量。

 7.选 WebFlux 还是 Spring MVC?

首先你需要明确一点就是:WebFlux 不是 Spring MVC 的替代方案!,虽然 WebFlux 也可以被运行在 Servlet 容器上(需是 Servlet 3.1+ 以上的容器),但是 WebFlux 主要还是应用在异步非阻塞编程模型,而 Spring MVC 是同步阻塞的,如果你目前在 Spring MVC 框架中大量使用非同步方案,那么,WebFlux 才是你想要的,否则,使用 Spring MVC 才是你的首选。

在微服务架构中,Spring MVC 和 WebFlux 可以混合使用,比如已经提到的,对于那些 IO 密集型服务(如网关),我们就可以使用 WebFlux 来实现。

 总之一句话,在合适的场景中,选型最合适的技术。

 8.总结

本篇主要讲解WebFlux 响应式编程,WebFlux的概念,Reactor 的Mono Flux ,以及WebFlux的优点和使用场景 WebFlux 是Spring5提供的 基于Reactor 框架(它实现Reactive Streams一种支持背压(Backpressure)的异步数据流处理标准),Spring WebFlux默认集成Reactor

本篇只是简单入门体验了一下WebFlux 后续会选一款具有响应式机制的数据库 Mongodb等 写一篇完整的基于WebFlux的响应式的CRUD案例,更深入理解一下WebFlux编程模式 加油吧!


以上是关于WebFlux 响应式编程初体验的主要内容,如果未能解决你的问题,请参考以下文章

RAC初体验

Stream流编程——Webflux响应式编程利器

SpringBoot使用WebFlux响应式编程操作数据库

话说Spring 5里的WebFlux到底是个啥?

WebFlux响应式编程

Java响应式编程Springboot WebFlux基础与实战