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