javascript
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是這樣做的:線程發(fā)現(xiàn)文件還沒準備好,就先去做其它事情,當文件準備好之后,通知這根線程來處理,當接收完畢寫入磁盤的時候(根據(jù)具體情況選擇是否做異步非阻塞),寫入完畢后通知這根線程再來處理(異步非阻塞情況下)。這個用腳趾頭都能看出相對SpringMVC而言,可以節(jié)省系統(tǒng)資源。666啊,有木有!
響應式(reactive)函數(shù)編程
如果你覺得java8的lambda寫起來很爽,那么,你會再次喜歡上Spring WebFlux,因為它支持函數(shù)式編程,得益于對于reactive-stream的支持(通過reactor框架來實現(xiàn)的),喜歡java8 stream的又有福了。為什么要函數(shù)式編程? 這個別問我,我也不知道,或許是因為bi格高吧,哈哈,開玩笑啦。
不再拘束于Servlet容器
以前,我們的應用都運行于Servlet容器之中,例如我們大家最為熟悉的Tomcat, Jetty...等等。而現(xiàn)在Spring WebFlux不僅能運行于傳統(tǒng)的Servlet容器中(前提是容器要支持Servlet3.1,因為非阻塞IO是使用了Servlet3.1的特性),還能運行在支持NIO的Netty和Undertow中。
所以,看完Spring WebFlux的新特性之后,內心五味雜陳的我,只能用一個表情來形容:
但是學習還是要學的,畢竟Spring推出的......
Spring WebFlux是隨Spring 5推出的響應式Web框架。建立在異步非阻塞的IO框架之上的一個新的,其基本的架構如下:
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注解方式實現(xiàn)
Spring團隊在開發(fā)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類型的數(shù)據(jù),因此使用Mono.just(T t) 構造
可以看大,執(zhí)行的結果如下:
$ curl -X GET http://localhost:8080/mono Hello,Reactive Program效果和SpringMVC 并無區(qū)別,同樣的我們返回集合列表查看效果
@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?
首先看著這兩者并無區(qū)別,其實實際上和文章首頁的架構圖示一樣,其底層核心的變了,實現(xiàn)接口,并再是基于Servlet,而是基于Http/Reactive Stream ,我們在接口方法添加參數(shù)
@GetMapping("/flux")public Flux<String> getFluxString(HttpServerRequest request) {....}此時訪問flux接口,會報錯
java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.http.HttpRequest
意思是非法的狀態(tài)異常,沒有org.springframework.http.HttpRequest的構造參數(shù)被發(fā)現(xiàn),這說明WebFlux的實現(xiàn)已經不再是Serverlet了
實現(xiàn)Server Send Event
下面我是實現(xiàn)SSE(服務器推送),注意這里和Socket有所區(qū)別,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)表示推送的次數(shù),沒有take表示無限流,times表示推送的次數(shù),我們在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"}需要注意的是,在創(chuàng)建時間上,是每個1s鐘由服務器推送過來的,這是和SpringMVC有著巨大的區(qū)別.
RouterFunctin 實現(xiàn)方式
Spring團隊在實現(xiàn)WebFlux的有了另外的實現(xiàn)方式,利用RouterFuntion & HandleFunction,這里不做過多的贅述,這種方式的效果和上述效果一致,可以對比學習,代碼如下:
向Spring容器中注入RouterFunctionBean對象
@Configuration public class RouteConfig {@Beanpublic RouterFunction<ServerResponse> timeRoute(){return route(GET("/time"),TimeHandle::getTime).andRoute(GET("/sse"),TimeHandle::sendTimeWithSSE);} }具體邏輯實現(xiàn)
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);}// 實現(xiàn)時間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);} }整體來說還是比較簡單的,請繼續(xù)關注后期的WebFlux的學習過程~
參考文章
【CSDN】(5)Spring WebFlux快速上手——響應式Spring的道法術器
【IBM developerWorks】使用 Spring 5 的 WebFlux 開發(fā)反應式 Web 應用
轉載于:https://www.cnblogs.com/zhoutao825638/p/10382275.html
總結
以上是生活随笔為你收集整理的Spring WebFlux 响应式编程学习笔记(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mac OS上用item2连接CentO
- 下一篇: JQuery 加载 CSS、JS 文件