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這麼好的框架了嗎,爲何還要推出這個?react

衆所周知,SpringMVC是同步阻塞的IO模型,資源浪費相對來講比較嚴重,當咱們在處理一個比較耗時的任務時,好比寫文件到磁盤中,這期間容器線程(Tomcat線程)會一直在等待處理完成返回結果才能去接收其餘的請求,這不是浪費資源嗎?這就是Spring WebFlux 推出的緣由!web

 2.WebFlux的概念

 先看圖:spring

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

相關文章
相關標籤/搜索