javascript
Spring 5 新增全新的reactive web框架:webflux
Spring 5發(fā)布了一個非常重要的模塊,名字叫做:spring-webflux。該模塊平級的就是spring-webmvc。
?
?
具體能做什么呢?自然是mvc不擅長的事情了。自然是人們一直希望實現(xiàn),但總是比較困難的功能了。
先來看看flux是什么意思?
?
沒錯,是“流”的意思:stream,?flux,?rate,?class,?blast,?grade。
具體做什么事情呢?就是webflux可以讓你在web應用下也可以體驗tcp長連接傳輸流數(shù)據(jù)的快感了。這在過去我們都是通過一些奇技淫巧才能實現(xiàn)的能力。
官方說法就是webflux是一個完全的reactive并且非阻塞的web框架。
?
什么是響應式編程?簡單點說就是非阻塞,異步的而且是事件驅動的,只需要少量的線程,在一個jvm中垂直擴展而已,而不用通過集群的水平擴展方式。
?
webmvc與webflux
webmvc是servlet stack ?based,而webflux是reactive stack based。
?
?
Spring MVC的大名是響當當?shù)?#xff0c;但是可能讓你驚奇的是,居然沒有給這個名字實際的項目或獨立的分配。相反,它是Spring Framework中的一個模塊,叫做spring-webmvc。這真的是一個讓人覺得略怪的事情。居然不是一個頂級項目,而是在org.springframework.web.servlet下。好了,不糾結這些細節(jié)了。
?
Spring reative Web框架,是5.0中的新功能,是一個完全的reactive并且非阻塞的web框架。它適合處理那種event-loop 風格的事情,也就是事件驅動的。它支持Servlet容器(Tomcat,Jetty,Servlet 3.1+),也支持非Servlet的運行時(比如:Netty,Undertow),因為它的基礎不是Servlet API,而是構建在Reactive Streams和Reactor項目之上的。
?
在5中,spring-web-reactive模塊被改名為spring-webflux 。新模塊中的頂級包是org.springframework.web.reactive。
?
哈哈,既然mvc就沒有一個頂級的待遇,現(xiàn)在webflux也一樣,都在web下,一個叫servlet,一個叫reactive。
?
你可以這樣理解:就是servlet和reative是內部的真實情況,而webmvc和webflux則是為了迎合和搶占業(yè)界的一些主流概念。一個務實一個務虛。
?
SSE
另外還有一個概念就是SSE。就是Server-sent events的縮寫。這是個什么鬼。其實就是個概念。或者是一個標準。就是把數(shù)據(jù)從web服務端傳輸?shù)娇蛻舳说囊环N做法。顧名思義:服務端發(fā)送給客戶端的事件。神奇吧。
?
你就先這么理解吧。一會我們會上代碼,而且會具體演示效果。
?
實現(xiàn)和演示
?
鋪墊
?
我們會先通過傳統(tǒng)的webmvc的方式來實現(xiàn)reactive效果。然后我們會使用spring 5 的 webflux 再來實現(xiàn)一次reactive效果。
?
傳統(tǒng)的實現(xiàn)方式
?
先通過spring initializr新建一個普通的spring boot應用。
?
pom
然后在pom中添加一個web依賴和一個integration-file依賴(稍后會用到):
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-file</artifactId> </dependency>代碼
?
/*** @author hezhuofan*/ @SpringBootApplication @RestController public class RegularSseApplication {private final Map<String, SseEmitter> sses = new ConcurrentHashMap<>();@Beanpublic IntegrationFlow inboundFlow(@Value("${input-dir:file://${HOME}/Desktop/in}") File in) {System.out.println(in.getAbsolutePath());return IntegrationFlows.from(Files.inboundAdapter(in).autoCreateDirectory(true), poller -> poller.poller(spec -> spec.fixedRate(1000L))).transform(File.class, File::getAbsolutePath).handle(String.class, (path, map) -> {sses.forEach((key, sse) -> {try {sse.send(path);} catch (Exception ex) {throw new RuntimeException();}});return null;}).channel(filesChannel()).get();}@BeanSubscribableChannel filesChannel() {return MessageChannels.publishSubscribe().get();}@GetMapping("/files/{name}")SseEmitter file(@PathVariable String name) {SseEmitter sseEmitter = new SseEmitter(60 * 1000L);sses.put(name, sseEmitter);return sseEmitter;}public static void main(String[] args) {SpringApplication.run(RegularSseApplication.class, args);} }?
基本思路
?
就是我們通過intergration file來把本地的一個指定目錄作為一個流綁定到指定的url :/files/${name}。
?
我們在桌面新建一個in目錄,in目錄新建文件。這時候啟動的web server端就會向客戶端返回 該文件的 絕對路徑,相當于通知給客戶端。
?
演示
?
?
左邊是服務端,右邊是客戶端。服務端in目錄下新建了文件,服務端檢測到后,立馬把新建的文件的絕對路徑發(fā)送給了客戶端。
?
新建文件命令:
touch fileName客戶端發(fā)送請求命令:
curl http://localhost:9995/files/spring?
webflux 實現(xiàn)
?
pom
之前是web,現(xiàn)在換成了webflux。其他沒變。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-file</artifactId> </dependency>值得注意的是,我們使用的是spring boot 2.0.0-SNAPSHOT版。因為flux是spring 5的內容。
?
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.0.BUILD-SNAPSHOT</version><relativePath/> <!-- lookup parent from repository --> </parent>代碼
?
@SpringBootApplication @RestController public class SpringSamplesWebfluxApplication {@GetMapping(value="files/{name}",produces = MediaType.TEXT_EVENT_STREAM_VALUE)Flux<String> files(@PathVariable String name) {return Flux.create((FluxSink<String> sink) -> {FluxSink<String> serialize = sink.serialize();MessageHandler handler = msg -> serialize.next(String.class.cast(msg.getPayload()));serialize.setCancellation(() -> filesChannel().unsubscribe(handler));filesChannel().subscribe(handler);});}@Beanpublic IntegrationFlow inboundFlow(@Value("${input-dir:file://${HOME}/Desktop/in}") File in) {System.out.println(in.getAbsolutePath());return IntegrationFlows.from(Files.inboundAdapter(in).autoCreateDirectory(true), poller -> poller.poller(spec -> spec.fixedRate(1000L))).transform(File.class, File::getAbsolutePath).channel(filesChannel()).get();}@BeanSubscribableChannel filesChannel() {return MessageChannels.publishSubscribe().get();}public static void main(String[] args) {SpringApplication.run(SpringSamplesWebfluxApplication.class, args);} }?
演示
?
為了區(qū)分是不同的實現(xiàn),我們使用了不同的端口。
?
左邊是服務端,右邊是客戶端。服務端in目錄下新建了文件,服務端檢測到后,立馬把新建的文件的絕對路徑發(fā)送給了客戶端。
?
新建文件命令:
touch fileName?
客戶端發(fā)送請求命令:
curl http://localhost:8765/files/spring?
總結
以上只是簡單的介紹了下來龍去脈,并且對基于web的sse實現(xiàn)做了演示,以及對基于flux實現(xiàn)的演示。webflux是一個全新的reactive非阻塞web框架。與webmvc在同一個層次。對于微服務下的IO密集型的service來說,webflux也許是一個不錯的嘗試或選擇吧。
總結
以上是生活随笔為你收集整理的Spring 5 新增全新的reactive web框架:webflux的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Boot 2.0 新特性和
- 下一篇: Spring Boot 2.0 新特性(