javascript
Spring WebFlux 响应式编程学习笔记(一)
各位Javaer們,大家都在用SpringMVC吧?當(dāng)我們不亦樂(lè)乎的用著SpringMVC框架的時(shí)候,Spring5.x又悄(da)無(wú)(zhang)聲(qi)息(gu)的推出了Spring WebFlux。web? 不是已經(jīng)有SpringMVC這么好用的東西了么,為啥又冒出個(gè)WebFlux? 這玩意兒是什么鬼?
Spring WebFlux特性
異步非阻塞
SpringMVC是同步阻塞的IO模型,資源浪費(fèi)相對(duì)來(lái)說(shuō)比較嚴(yán)重,當(dāng)我們?cè)谔幚硪粋€(gè)比較耗時(shí)的任務(wù)時(shí),例如:上傳一個(gè)比較大的文件,首先,服務(wù)器的線程一直在等待接收文件,在這期間它就像個(gè)傻子一樣等在那兒(放學(xué)別走),什么都干不了,好不容易等到文件來(lái)了并且接收完畢,我們又要將文件寫入磁盤,在這寫入的過(guò)程中,這根線程又再次懵bi了,又要等到文件寫完才能去干其它的事情。這一前一后的等待,不浪費(fèi)資源么?
沒(méi)錯(cuò),Spring WebFlux就是來(lái)解決這問(wèn)題的,Spring WebFlux可以做到異步非阻塞。還是上面那上傳文件的例子,Spring WebFlux是這樣做的:線程發(fā)現(xiàn)文件還沒(méi)準(zhǔn)備好,就先去做其它事情,當(dāng)文件準(zhǔn)備好之后,通知這根線程來(lái)處理,當(dāng)接收完畢寫入磁盤的時(shí)候(根據(jù)具體情況選擇是否做異步非阻塞),寫入完畢后通知這根線程再來(lái)處理(異步非阻塞情況下)。這個(gè)用腳趾頭都能看出相對(duì)SpringMVC而言,可以節(jié)省系統(tǒng)資源。666啊,有木有!
響應(yīng)式(reactive)函數(shù)編程
如果你覺(jué)得java8的lambda寫起來(lái)很爽,那么,你會(huì)再次喜歡上Spring WebFlux,因?yàn)樗С趾瘮?shù)式編程,得益于對(duì)于reactive-stream的支持(通過(guò)reactor框架來(lái)實(shí)現(xiàn)的),喜歡java8 stream的又有福了。為什么要函數(shù)式編程? 這個(gè)別問(wèn)我,我也不知道,或許是因?yàn)閎i格高吧,哈哈,開玩笑啦。
不再拘束于Servlet容器
以前,我們的應(yīng)用都運(yùn)行于Servlet容器之中,例如我們大家最為熟悉的Tomcat, Jetty...等等。而現(xiàn)在Spring WebFlux不僅能運(yùn)行于傳統(tǒng)的Servlet容器中(前提是容器要支持Servlet3.1,因?yàn)榉亲枞鸌O是使用了Servlet3.1的特性),還能運(yùn)行在支持NIO的Netty和Undertow中。
所以,看完Spring WebFlux的新特性之后,內(nèi)心五味雜陳的我,只能用一個(gè)表情來(lái)形容:
但是學(xué)習(xí)還是要學(xué)的,畢竟Spring推出的......
Spring WebFlux是隨Spring 5推出的響應(yīng)式Web框架。建立在異步非阻塞的IO框架之上的一個(gè)新的,其基本的架構(gòu)如下:
Spring提供了完整的支持響應(yīng)式的服務(wù)端技術(shù)棧。
如上圖所示,左側(cè)為基于spring-webmvc的技術(shù)棧,右側(cè)為基于spring-webflux的技術(shù)棧,可以看到SpringMVC技術(shù)棧給予Serverlet容器,如Tomcat容器,SpringWebFlux基于HTTP/Reactive Stream.
WebFlux 依賴構(gòu)建
依賴于SpringBoot的強(qiáng)大,我們只要在配置文件添加依賴即可。
Gradle 依賴
compile('org.springframework.boot:spring-boot-starter-webflux')或者M(jìn)aven構(gòu)建的依賴于
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId> </dependency>SpringMVC注解方式實(shí)現(xiàn)
Spring團(tuán)隊(duì)在開發(fā)WebFlux上盡量和SpringMVC靠攏,因此我們可以直接使用一個(gè)簡(jiǎn)單的SpringMVC項(xiàng)目有改造成Spring WebFlux的項(xiàng)目,具體如下。
改造 Spring MVC
下面是我們?cè)偈煜げ贿^(guò)的接口應(yīng)用,訪問(wèn)http://localhost:8080/mono 即可看到返回了一個(gè)字符串
@GetMapping("/mono")public String baseApi() {return "Hello,Reactive Program";}改造后的內(nèi)容如下:
@GetMapping("/mono")public Mono<String> baseApi() { //1return Mono.just("Hello,Reactive Program"); //2}主要有兩處改造
1 返回的不再是簡(jiǎn)單的對(duì)象,而是使用的是Mono封裝的單個(gè)文檔信息(返回集合使用Flux)
2 返回的時(shí)候我們需要構(gòu)造一個(gè)Mono類型的數(shù)據(jù),因此使用Mono.just(T t) 構(gòu)造
可以看大,執(zhí)行的結(jié)果如下:
$ curl -X GET http://localhost:8080/mono Hello,Reactive Program效果和SpringMVC 并無(wú)區(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));}分析過(guò)程
結(jié)果也和預(yù)期一致,那么不僅要思考了,同樣和SpringMVC達(dá)到一致的效果,為什么我們要用WebFlux?
首先看著這兩者并無(wú)區(qū)別,其實(shí)實(shí)際上和文章首頁(yè)的架構(gòu)圖示一樣,其底層核心的變了,實(shí)現(xiàn)接口,并再是基于Servlet,而是基于Http/Reactive Stream ,我們?cè)诮涌诜椒ㄌ砑訁?shù)
@GetMapping("/flux")public Flux<String> getFluxString(HttpServerRequest request) {....}此時(shí)訪問(wèn)flux接口,會(huì)報(bào)錯(cuò)
java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.http.HttpRequest
意思是非法的狀態(tài)異常,沒(méi)有org.springframework.http.HttpRequest的構(gòu)造參數(shù)被發(fā)現(xiàn),這說(shuō)明WebFlux的實(shí)現(xiàn)已經(jīng)不再是Serverlet了
實(shí)現(xiàn)Server Send Event
下面我是實(shí)現(xiàn)SSE(服務(wù)器推送),注意這里和Socket有所區(qū)別,Socket是雙向通信,這是單向通信,由服務(wù)器向客戶端推送消息
@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響應(yīng)式Web編程" + second).setPrice("12")).take(5);}模型Book需要lombok支持,沒(méi)有的話,請(qǐng)手動(dòng)完成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(); }首先說(shuō)明一下produces = MediaType.TEXT_EVENT_STREAM_VALUE 表示這是一個(gè)事件流,返回的是Flux類型,推送的間隔為1s,最后take(times)表示推送的次數(shù),沒(méi)有take表示無(wú)限流,times表示推送的次數(shù),我們?cè)趕hell中嘗試調(diào)用下,看看效果
$ curl -X GET http://localhost:8080/sse/object data:{"id":"0","name":"Flux響應(yīng)式Web編程0","price":"12","createTime":"2018-09-09T12:46:10.445+0000"}data:{"id":"1","name":"Flux響應(yīng)式Web編程1","price":"12","createTime":"2018-09-09T12:46:11.444+0000"}data:{"id":"2","name":"Flux響應(yīng)式Web編程2","price":"12","createTime":"2018-09-09T12:46:12.444+0000"}data:{"id":"3","name":"Flux響應(yīng)式Web編程3","price":"12","createTime":"2018-09-09T12:46:13.445+0000"}data:{"id":"4","name":"Flux響應(yīng)式Web編程4","price":"12","createTime":"2018-09-09T12:46:14.444+0000"}需要注意的是,在創(chuàng)建時(shí)間上,是每個(gè)1s鐘由服務(wù)器推送過(guò)來(lái)的,這是和SpringMVC有著巨大的區(qū)別.
RouterFunctin 實(shí)現(xiàn)方式
Spring團(tuán)隊(duì)在實(shí)現(xiàn)WebFlux的有了另外的實(shí)現(xiàn)方式,利用RouterFuntion & HandleFunction,這里不做過(guò)多的贅述,這種方式的效果和上述效果一致,可以對(duì)比學(xué)習(xí),代碼如下:
向Spring容器中注入RouterFunctionBean對(duì)象
@Configuration public class RouteConfig {@Beanpublic RouterFunction<ServerResponse> timeRoute(){return route(GET("/time"),TimeHandle::getTime).andRoute(GET("/sse"),TimeHandle::sendTimeWithSSE);} }具體邏輯實(shí)現(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);}// 實(shí)現(xiàn)時(shí)間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);} }整體來(lái)說(shuō)還是比較簡(jiǎn)單的,請(qǐng)繼續(xù)關(guān)注后期的WebFlux的學(xué)習(xí)過(guò)程~
參考文章
【CSDN】(5)Spring WebFlux快速上手——響應(yīng)式Spring的道法術(shù)器
【IBM developerWorks】使用 Spring 5 的 WebFlux 開發(fā)反應(yīng)式 Web 應(yīng)用
轉(zhuǎn)載于:https://www.cnblogs.com/zhoutao825638/p/10382275.html
總結(jié)
以上是生活随笔為你收集整理的Spring WebFlux 响应式编程学习笔记(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Mac OS上用item2连接CentO
- 下一篇: 关于修改了virc(增加了:set nu