Spring WebFlux 響應式編程學習筆記(一)

各位Javaer們,大家都在用SpringMVC吧?當我們不亦樂乎的用著SpringMVC框架的時候,Spring5.x又悄(da)無(zhang)聲(qi)息(gu)的推出了Spring WebFlux。web? 不是已經有SpringMVC這么好用的東西了么,為啥又冒出個WebFlux? 這玩意兒是什么鬼?

Spring WebFlux特性

異步非阻塞

SpringMVC是同步阻塞的IO模型,資源浪費相對來說比較嚴重,當我們在處理一個比較耗時的任務時,例如:上傳一個比較大的文件,首先,服務器的線程一直在等待接收文件,在這期間它就像個傻子一樣等在那兒(放學別走),什么都干不了,好不容易等到文件來了并且接收完畢,我們又要將文件寫入磁盤,在這寫入的過程中,這根線程又再次懵bi了,又要等到文件寫完才能去干其它的事情。這一前一后的等待,不浪費資源么?

沒錯,Spring WebFlux就是來解決這問題的,Spring WebFlux可以做到異步非阻塞。還是上面那上傳文件的例子,Spring WebFlux是這樣做的:線程發現文件還沒準備好,就先去做其它事情,當文件準備好之后,通知這根線程來處理,當接收完畢寫入磁盤的時候(根據具體情況選擇是否做異步非阻塞),寫入完畢后通知這根線程再來處理(異步非阻塞情況下)。這個用腳趾頭都能看出相對SpringMVC而言,可以節省系統資源。666啊,有木有!

響應式(reactive)函數編程

如果你覺得java8的lambda寫起來很爽,那么,你會再次喜歡上Spring WebFlux,因為它支持函數式編程,得益于對于reactive-stream的支持(通過reactor框架來實現的),喜歡java8 stream的又有福了。為什么要函數式編程? 這個別問我,我也不知道,或許是因為bi格高吧,哈哈,開玩笑啦。

不再拘束于Servlet容器

以前,我們的應用都運行于Servlet容器之中,例如我們大家最為熟悉的Tomcat, Jetty...等等。而現在Spring WebFlux不僅能運行于傳統的Servlet容器中(前提是容器要支持Servlet3.1,因為非阻塞IO是使用了Servlet3.1的特性),還能運行在支持NIO的Netty和Undertow中。

所以,看完Spring WebFlux的新特性之后,內心五味雜陳的我,只能用一個表情來形容:

bq__%E4%BB%80%E4%B9%88%E7%8E%A9%E6%84%8F.jpg

但是學習還是要學的,畢竟Spring推出的......

Spring WebFlux是隨Spring 5推出的響應式Web框架。建立在異步非阻塞的IO框架之上的一個新的,其基本的架構如下:
getImage?fileId=5a929813ab644121e3000f8c

Spring提供了完整的支持響應式的服務端技術棧。

如上圖所示,左側為基于spring-webmvc的技術棧,右側為基于spring-webflux的技術棧,可以看到SpringMVC技術棧給予Serverlet容器,如Tomcat容器,SpringWebFlux基于HTTP/Reactive Stream.

WebFlux 依賴構建

依賴于SpringBoot的強大,我們只要在配置文件添加依賴即可。

Gradle 依賴

    compile('org.springframework.boot:spring-boot-starter-webflux')

或者Maven構建的依賴于

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

SpringMVC注解方式實現

Spring團隊在開發WebFlux上盡量和SpringMVC靠攏,因此我們可以直接使用一個簡單的SpringMVC項目有改造成Spring WebFlux的項目,具體如下。

改造 Spring MVC

下面是我們再熟悉不過的接口應用,訪問http://localhost:8080/mono 即可看到返回了一個字符串

   @GetMapping("/mono")public String baseApi() {return "Hello,Reactive Program";}

改造后的內容如下:

    @GetMapping("/mono")public Mono<String> baseApi() {                  //1return Mono.just("Hello,Reactive Program");   //2}

主要有兩處改造

  • 1 返回的不再是簡單的對象,而是使用的是Mono封裝的單個文檔信息(返回集合使用Flux)

  • 2 返回的時候我們需要構造一個Mono類型的數據,因此使用Mono.just(T t) 構造

可以看大,執行的結果如下:

$ curl -X GET http://localhost:8080/mono
Hello,Reactive Program

效果和SpringMVC 并無區別,同樣的我們返回集合列表查看效果

    @GetMapping("/flux")public Flux<String> getFluxString() {String[] dataSet = new String[]{"This is 1", "This is 2", "This is 3", "This is 4"};return Flux.fromIterable(Arrays.asList(dataSet));}

分析過程

結果也和預期一致,那么不僅要思考了,同樣和SpringMVC達到一致的效果,為什么我們要用WebFlux?

首先看著這兩者并無區別,其實實際上和文章首頁的架構圖示一樣,其底層核心的變了,實現接口,并再是基于Servlet,而是基于Http/Reactive Stream ,我們在接口方法添加參數

    @GetMapping("/flux")public Flux<String> getFluxString(HttpServerRequest request) {....}

此時訪問flux接口,會報錯

java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.http.HttpRequest

意思是非法的狀態異常,沒有org.springframework.http.HttpRequest的構造參數被發現,這說明WebFlux的實現已經不再是Serverlet了

實現Server Send Event

下面我是實現SSE(服務器推送),注意這里和Socket有所區別,Socket是雙向通信,這是單向通信,由服務器向客戶端推送消息

    @GetMapping(value = "/sse/object", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<Book> sseBook() {return Flux.interval(Duration.ofSeconds(1)).map(second ->new Book().setId(Stirng.valueOf(second)).setName("深入淺出Flux響應式Web編程" + second).setPrice("12")).take(5);}

模型Book需要lombok支持,沒有的話,請手動完成set、get方法,并在Set方法尾部return this


@Data
@Accessors(chain = true)
public class Book {private String id;private String name;private String price;private Date createTime = new Date();
}

首先說明一下produces = MediaType.TEXT_EVENT_STREAM_VALUE 表示這是一個事件流,返回的是Flux類型,推送的間隔為1s,最后take(times)表示推送的次數,沒有take表示無限流,times表示推送的次數,我們在shell中嘗試調用下,看看效果

$ curl -X GET http://localhost:8080/sse/object
data:{"id":"0","name":"Flux響應式Web編程0","price":"12","createTime":"2018-09-09T12:46:10.445+0000"}data:{"id":"1","name":"Flux響應式Web編程1","price":"12","createTime":"2018-09-09T12:46:11.444+0000"}data:{"id":"2","name":"Flux響應式Web編程2","price":"12","createTime":"2018-09-09T12:46:12.444+0000"}data:{"id":"3","name":"Flux響應式Web編程3","price":"12","createTime":"2018-09-09T12:46:13.445+0000"}data:{"id":"4","name":"Flux響應式Web編程4","price":"12","createTime":"2018-09-09T12:46:14.444+0000"}

需要注意的是,在創建時間上,是每個1s鐘由服務器推送過來的,這是和SpringMVC有著巨大的區別.

RouterFunctin 實現方式

Spring團隊在實現WebFlux的有了另外的實現方式,利用RouterFuntion & HandleFunction,這里不做過多的贅述,這種方式的效果和上述效果一致,可以對比學習,代碼如下:

向Spring容器中注入RouterFunctionBean對象

@Configuration
public class RouteConfig {@Beanpublic RouterFunction<ServerResponse> timeRoute(){return route(GET("/time"),TimeHandle::getTime).andRoute(GET("/sse"),TimeHandle::sendTimeWithSSE);}
}

具體邏輯實現

public class TimeHandle {private static SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");public static Mono<ServerResponse>  getTime(ServerRequest serverRequest){return ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(Mono.just(simpleDateFormat.format(new Date())),String.class);}// 實現時間SSE推送注意MediaType類型public static Mono<ServerResponse> sendTimeWithSSE(ServerRequest serverRequest){return  ok().contentType(MediaType.TEXT_EVENT_STREAM).body(Flux.interval(Duration.ofSeconds(1)).map(value -> simpleDateFormat.format(new Date())),String.class);}
}

整體來說還是比較簡單的,請繼續關注后期的WebFlux的學習過程~

參考文章

  • 【CSDN】(5)Spring WebFlux快速上手——響應式Spring的道法術器

  • 【IBM developerWorks】使用 Spring 5 的 WebFlux 開發反應式 Web 應用

轉載于:https://www.cnblogs.com/zhoutao825638/p/10382275.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/449463.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/449463.shtml
英文地址,請注明出處:http://en.pswp.cn/news/449463.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Django Rest Framework -解析器

基本代碼結構 urls.py rom django.conf.urls import url, include from web.views.s5_parser import TestViewurlpatterns [url(rtest/, TestView.as_view(), nametest), ]views.py from rest_framework.views import APIView from rest_framework.response import Response f…

真格量化——菜粕策略

#!/usr/bin/env python # coding:utf-8 from PoboAPI import * import datetime import time import numpy as np from copy import *#開始時間,用于初始化一些參數 def OnStart(context) :context.myacc = None#登錄交易賬號if context.accounts["回測期貨"].Login…

PostgreSQL查看版本信息

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1.查看客戶端版本 psql --version 1 2.查看服務器端版本 2.1 查看詳細信息 select version(); 1 2.2 查看版本信息 show server_ve…

U盤版便攜式Linux制作, casper-rw 解析

一直都在想&#xff0c;不管用誰的電腦&#xff0c;我都可以得到一個完全一致的工作環境&#xff0c;上面有我喜愛的軟件&#xff0c;有我保存的重要資料&#xff0c;甚至瀏覽器的各種偏好都得一模一樣&#xff01;現在的云計算技術可以部分解決這個問題&#xff0c;但是遠遠不…

真格量化-50ETF期權波動率策略

#!/usr/bin/env python # coding:utf-8 from PoboAPI import * import datetime import time import numpy as np #日線級別 #開始時間,用于初始化一些參數 def OnStart(context) :print("I\m starting...")#設定一個全局變量品種,本策略交易50ETF期權g.code = Get…

canvas反向裁剪技巧

我們都知道在canvas 可以通過clip來實現剪裁功能&#xff0c;其步驟一般是先設置要裁剪的區域&#xff08;路徑&#xff09;&#xff0c;然后通過ctx.clip()的實現裁剪&#xff0c;裁剪之后&#xff0c;后續的繪制只能在裁剪的區域顯示效果&#xff0c;比如如下一段代碼&#x…

set 和select 的區別

簡單賦值是沒有區別的 轉載于:https://www.cnblogs.com/bingyizhihun/p/10597908.html

postgres大版本升級

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。進行升級版本之前請一定做好備份&#xff01;查看當前版本&#xff1a;[postgresnode1 ~]$ psqlpsql (9.4.4)Type "help" for h…

馬上有錢:揭密25種成為有錢人的方法(圖)

1、做你真正感興趣的事—你會花很多時間在上面&#xff0c;因此你一定要感興趣才行&#xff0c;如果不是這樣的話&#xff0c;你不愿意把時間花在上面&#xff0c;就得不到成功。 2、自己當老板。為別人打工&#xff0c;你絕不會變成巨富&#xff0c;老板一心一意地縮減開支&a…

無人承運平臺系統流程圖

轉載于:https://www.cnblogs.com/procedureMonkey/p/10598052.html

Neither the JAVA_HOME nor the JRE_HOME environment variable is defined

Centos7.5 啟動tomcat報錯 報錯: Neither the JAVA_HOME nor the JRE_HOME environment variable is defined At least one of these environment variable is needed to run this program原因:沒有安裝java 解決方法:安裝java yum install java -y轉載于:https://www.cnblogs…

讓自己變成一個上進的人

1.認真設計你的環境2.引入外部監督 求“綁架”3.獲取不確定的反饋4.選擇一條既細密&#xff0c;又永無止境的職業上升臺階。轉載于:https://www.cnblogs.com/Julietma/p/10600241.html

年買筆記本的8個小技巧 最適合自己才最好(組圖)

顯然&#xff0c;智能手機和平板在一定程度上可以替代傳統電腦&#xff0c;讓我們可以隨時隨地上網、使用各種應用。不過&#xff0c;傳統電腦也擁有它的不可替代性&#xff0c;比如移動辦公、視頻編輯、玩游戲&#xff0c;筆記本電腦可能是個更好的選擇。 作為一種成熟的電腦…

MySql查詢系統時間,SQLServer查詢系統時間,Oracle查詢系統時間

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 MySQL查詢系統時間 第一種方法&#xff1a;select current_date&#xff1b; MySQL> select current_date as Systemtime; 第二…

flask同源策略解決辦法及flask-cors只允許特定域名跨域

falsk 同源策略解決辦法&#xff1a; 使用 flask-cors 包 并且 在代碼里 加響應的一行代碼解決。 from flask import Flask, session from flask_cors import CORSapp Flask(__name__) CORS(app, resources{r"/*": {"origins": "*"}}) # 允許…

基本變量和引用變量

基本數據類型作比較&#xff0c;值相等則相等&#xff0c;值不相等則不相等&#xff08;忽略數據類型&#xff09; 引用類型作比較&#xff0c;引用地址相等則相等&#xff0c;否則都是不等的。 基本數據類型&#xff0c;和引用數據類型作比較&#xff0c;是比較值是否相等&…

真格量化-持倉量第n檔賣方主力跟隨策略

#!/usr/bin/env python # coding:utf-8 from PoboAPI import * import datetime import time import numpy as np import pandas as pd #日線級別 #開始時間,用于初始化一些參數 def OnStart(context):print("I\m starting...")#設定一個全局變量品種,本策略交易50E…

賺大錢必備 怎樣成為賺錢高手(圖)

1、一旦有賺錢的念頭就馬上一步一個腳印去做&#xff0c;要付諸行動&#xff0c;敢于碰&#xff0c;善于磨&#xff0c;只有這樣才能抓住機會。 2、想賺錢&#xff0c;就要立志當商人&#xff0c;而且目標要高&#xff0c;選定十萬、二十萬&#xff0c;再是一百萬、五百萬。 …

不定長圖片驗證碼訓練

基于LSTM和CTCLoss訓練不定長圖片驗證碼 Github項目地址&#xff1a;https://github.com/JansonJo/captcha_ocr.git # codingutf-8 """ 將三通道的圖片轉為灰度圖進行訓練 """ import itertools import os import re import random import strin…

[云框架]KONG API Gateway v1.5 -框架說明、快速部署、插件開發

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 當前版本采用KONGv0.12.3 當我們決定對應用進行微服務改造時&#xff0c;應用客戶端如何與微服務交互的問題也隨之而來&#xff0c;畢竟…