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这么好的框架了吗,为何还要推出这个?react
众所周知,SpringMVC是同步阻塞的IO模型,资源浪费相对来讲比较严重,当咱们在处理一个比较耗时的任务时,好比写文件到磁盘中,这期间容器线程(Tomcat线程)会一直在等待处理完成返回结果才能去接收其余的请求,这不是浪费资源吗?这就是Spring WebFlux 推出的缘由!!web
2.WebFlux的概念
先看图:spring
左边是传统的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上,支持很高的并发量浏览器
非阻塞的概念:网络
- WebFlux一个线程里能够处理更多的请求
- 老的开发模式:一个请求会对应容器里的一个线程
运行环境的不一样:架构
- 老的开发模式:基于ServletAPI,即运行在Servlet容器上面
- Webflux开发模式:基于响应式流,能够运行在Servlet3.1以后的容器(异步Servlet容器)或Netty上
数据库的不一样:并发
- 目前关系型数据库都是不支持响应式(基于JDBC)的数据库
- Reactive stack的SpringDataReactiveRepositories是:Mongo,Cassandra,Redis,Couchbase
3.WebFlux 初体验
2.1 建立项目
经过IDEA 建立SpringBoot2.0 项目,记得勾选 Spring Reactive Web 依赖
pom.xml 里会自动添加以下依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
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秒钟
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编程模式 加油吧!