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的概念

 先看图:

Xnip20200229_134034.png

 左边是传统的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 依赖


Xnip20200229_141909.png

  pom.xml 里会自动添加如下依赖

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

Xnip20200229_142056.png

  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秒钟

Xnip20200229_142559.png

  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毫秒,该线程就已经可以去接收其他请求了


Xnip20200229_143414.png

 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 密集型,使用异步非阻塞式编程模型,能够显著地提升网关对下游服务转发的吞吐量。
Xnip20200229_151348.png

 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编程模式 加油吧!

个人博客网站 https://www.askajohnny.com 欢迎来访问!
本文由博客一文多发平台 OpenWrite 发布!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容