Spring5.0 WebFlux入門及實戰示例

什麼是 Spring WebFlux

  • WebFlux是Spring推出響應式編程的一部分(web端)
  • 響應式編程是異步非阻塞的(是一種基於數據流(data stream)和變化傳遞(propagation of change)的聲明式(declarative)的編程範式)

Spring MVC 構建於 Servlet API 之上,使用的是同步阻塞式 I/O 模型,什麼是同步阻塞式 I/O 模型呢?就是說,每一個請求對應一個線程去處理。

Spring WebFlux 是一個異步非阻塞式的 Web 框架,它能夠充分利用多核 CPU 的硬件資源去處理大量的併發請求。

 

WebFlux 的優勢&提升性能?

WebFlux 內部使用的是響應式編程(Reactive Programming),以 Reactor 庫爲基礎, 基於異步和事件驅動,可以讓我們在不擴充硬件資源的前提下,提升系統的吞吐量和伸縮性。

看到這裏,你是不是以爲 WebFlux 能夠使程序運行的更快呢?量化一點,比如說我使用 WebFlux 以後,一個接口的請求響應時間是不是就縮短了呢?

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

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

WebFlux 並不能使接口的響應時間縮短,它僅僅能夠提升吞吐量和伸縮性

 

WebFlux 應用場景

  • 上面說到了, Spring WebFlux 是一個異步非阻塞式的 Web 框架,所以,它特別適合應用在 IO 密集型的服務中,比如微服務網關這樣的應用中。

PS: IO 密集型包括:磁盤IO密集型, 網絡IO密集型,微服務網關就屬於網絡 IO 密集型,使用異步非阻塞式編程模型,能夠顯著地提升網關對下游服務轉發的吞吐量。

  • 比如一個日誌監控系統,我們的前端頁面將不再需要通過“命令式”的輪詢的方式不斷向服務器請求數據然後進行更新,而是在建立好通道之後,數據流從系統源源不斷流向頁面,從而展現實時的指標變化曲線;
  • 再比如一個社交平臺,朋友的動態、點贊和留言不是手動刷出來的,而是當後臺數據變化的時候自動體現到界面上的。

 

選 WebFlux 還是 Spring MVC?

首先你需要明確一點就是:WebFlux 不是 Spring MVC 的替代方案!,雖然 WebFlux 也可以被運行在 Servlet 容器上(需是 Servlet 3.1+ 以上的容器),但是 WebFlux 主要還是應用在異步非阻塞編程模型,而 Spring MVC 是同步阻塞的,如果你目前在 Spring MVC 框架中大量使用非同步方案,那麼,WebFlux 纔是你想要的,否則,使用 Spring MVC 纔是你的首選。

在微服務架構中,Spring MVC 和 WebFlux 可以混合使用,比如已經提到的,對於那些 IO 密集型服務(如網關),我們就可以使用 WebFlux 來實現。

選 WebFlux 還是 Spring MVC? This is not a problem!

咱不能爲了裝逼而裝逼,爲了技術而技術,還要考量到轉向非阻塞響應式編程學習曲線是陡峭的,小組成員的學習成本等諸多因素。

總之一句話,在合適的場景中,選型最合適的技術

 

注意點

  • Spring MVC 因爲是使用的同步阻塞式,更方便開發人員編寫功能代碼,Debug 測試等,一般來說,如果 Spring MVC 能夠滿足的場景,就儘量不要用 WebFlux;
  • WebFlux 默認情況下使用 Netty 作爲服務器;
  • WebFlux 不支持 MySql;

 

入門WebFlux示例

maven依賴包

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

下面我們來看一個簡單的例子(基於WebFlux環境構建):

// 阻塞5秒鐘
private String createStr() {
    try {
        TimeUnit.SECONDS.sleep(5);
    } catch (InterruptedException e) {
    }
    return "some string";
}

// 普通的SpringMVC方法
@GetMapping("/1")
private String get1() {
    log.info("get1 start");
    String result = createStr();
    log.info("get1 end.");
    return result;
}

// WebFlux(返回的是Mono)
@GetMapping("/2")
private Mono<String> get2() {
    log.info("get2 start");
    Mono<String> result = Mono.fromSupplier(() -> createStr());
    log.info("get2 end.");
    return result;
}

我們分別來訪問一下SpringMVC的接口和WebFlux的接口,看一下有什麼區別:

SpringMVC:

img

WebFlux:

img

從調用者(瀏覽器)的角度而言,是感知不到有什麼變化的,因爲都是得等待5s才返回數據。但是,從服務端的日誌我們可以看出,WebFlux是直接返回Mono對象的(而不是像SpringMVC一直同步阻塞5s,線程才返回)。

這正是WebFlux的好處:能夠以固定的線程來處理高併發(充分發揮機器的性能)。

 

WebFlux還支持服務器推送(SSE - >Server Send Event),我們來看個例子:

/**
  * Flux : 返回0-n個元素
  * 注:需要指定MediaType
  * @return
  */
@GetMapping(value = "/3", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
private Flux<String> flux() {
    Flux<String> result = Flux
        .fromStream(IntStream.range(1, 5).mapToObj(i -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
            return "flux data--" + i;
        }));
    return result;
}

效果就是每秒會給瀏覽器推送數據:

img

 

Reference

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章