前言
???目前Spring boot2.0技術(shù)棧分為了2個技術(shù)體系著蟹,一種是響應(yīng)式技術(shù)棧拢切,一種是傳統(tǒng)Servlet技術(shù)棧违寿。如下圖:
???在構(gòu)建微服務(wù)的時候食听,我們可以根據(jù)情況來決定3種架構(gòu)方式:
1、完全響應(yīng)式
這種方式就是從網(wǎng)關(guān)到基礎(chǔ)設(shè)施層昏名,使用的都是響應(yīng)式的框架,但目前數(shù)據(jù)庫方面只支持mongo和Cassandra及redis等阵面,如果有用到mysql的場景則暫時不適用轻局。
2、混合式
由于使用部分數(shù)據(jù)庫的場景是無法使用響應(yīng)式的样刷,比如mysql仑扑,所以在mysql以外的部分可以采用響應(yīng)式。
3置鼻、完全命令式
??使用Servlet Stack夫壁,對所有組件都支持。
最后總結(jié)響應(yīng)式和命令式的優(yōu)缺點:
??優(yōu)點:在IO密集型場景時沃疮,雖然代碼運行性能不會提升盒让,但可以有效的提升吞吐量,比如請求數(shù)據(jù)庫司蔬,或者微服務(wù)中下游服務(wù)響應(yīng)比較長邑茄,當你進行一個請求時,會用一個Pushlisher來替代阻塞的過程俊啼,調(diào)用者可以注冊這個Pushlisher肺缕,這樣的話,在之后數(shù)據(jù)庫或下一層服務(wù)返回結(jié)果的時候授帕,就會通知Publisher同木,然后Publisher會通知調(diào)用者。
??缺點:寫入的代碼和執(zhí)行的代碼分離開來跛十,導(dǎo)致閱讀和編寫代碼的難度增加彤路,對于這種異步的代碼,編寫單元測試和調(diào)試代碼都很困難芥映。
??在之前進行微服務(wù)架構(gòu)的實踐中洲尊,本人也是使用了第2種微服務(wù)架構(gòu)方式,也就是混合式奈偏,使用spring cloud gateway作為網(wǎng)關(guān)坞嘀,gateway是一款基于Spring WebFlux的網(wǎng)關(guān)組件,所以也是對WebFlux做了一下研究惊来,并為后續(xù)的構(gòu)建響應(yīng)式微服務(wù)打好基礎(chǔ)丽涩。
對比傳統(tǒng)的Spring WebMVC和響應(yīng)式Spring WebFlux
??在圖中,左側(cè)為spring-webmvc的技術(shù)棧裁蚁,右側(cè)為spring-webflux的技術(shù)棧矢渊。Spring WebFlux是基于響應(yīng)式流的检眯,因此,可以建立異步的昆淡、非阻塞的锰瘸、事件驅(qū)動的服務(wù)。它采用Reactor作為首選的響應(yīng)式流的實現(xiàn)庫昂灵,并且也提供了對RxJava的支持避凝。而傳統(tǒng)的Spring WebMVC構(gòu)建在Java EE的servlet標準之上,該標準本身就是阻塞式和同步的眨补。在最新版的Servlet中也添加了異步支持管削,但是在等待請求的過程中,Servlet仍然在線程池中保持著線程撑螺。
Spring-WebFlux可以運行在Tomcat含思,Jetty,Netty甘晤,Undertow含潘,Servlet3.1+等多個容器上,默認使用Netty线婚。這里要提一個在Spring cloud gateway使用時遇到的容器的坑遏弱,gateway只能運行在netty上,否則qps會大大下降塞弊。參照我的文章:http://www.reibang.com/p/dde1b00cbbaa
Spring MVC和Spring WebFlux的關(guān)系
??請看下圖漱逸,既有共同的部分,也有互相獨立的部分游沿。
WebFlux的使用場景
??在微服務(wù)架構(gòu)體系中饰抒,WebFlux和WebMVC可以混合使用。而在IO密集型服務(wù)時诀黍,我們可以優(yōu)先選擇WebFlux去實現(xiàn)袋坑。比如web網(wǎng)關(guān)spring cloud gateway就是使用了基于WebFlux的實現(xiàn),在運行時間上蔗草,響應(yīng)式和非阻塞并不能讓程序運行的更快咒彤,相反還要稍微增加一些處理時間疆柔,可能還會稍微變慢咒精,那么gateway為什么要用它呢,因為網(wǎng)關(guān)是一個IO密集型服務(wù)旷档,如果下層服務(wù)的網(wǎng)絡(luò)變慢或不可靠模叙,那么響應(yīng)式所能體現(xiàn)出來的巨大差異就顯示出來了。
說回WebFlux
??前邊說過WebFlux采用Reactor作為首選的響應(yīng)式流的實現(xiàn)庫鞋屈,Mono和Flux是Reactor中兩個基礎(chǔ)概念范咨,Mono包含了0..1個元素序列故觅,F(xiàn)lux包含了0..N個元素序列。Mono和Flux都是發(fā)布者渠啊,實現(xiàn)了Publisher<T>输吏。在WebFlux中,方法只返回Mono和Flux替蛉,代碼基本也只和 Mono 或 Flux 打交道贯溅。而 Web Flux 則會實現(xiàn) Subscriber ,onNext 時將業(yè)務(wù)開發(fā)人員編寫的 Mono 或 Flux 轉(zhuǎn)換為 HTTP Response 返回給客戶端躲查。WebFlux有兩種不同的編程風(fēng)格它浅,分別是基于Spring MVC的注解和基于函數(shù)式路由。
基于Spring MVC
@RestController
public class HelloController {
@RequestMapping("sayOneHello")
public Mono<String> sayOneHello() {
return Mono.just("Hello World");
}
@RequestMapping("sayMoreHello")
public Flux<String> sayMoreHello() {
return Flux.fromIterable(new ArrayList<String>() {
{
add("Hello World one");
add("Hello World two");
add("Hello World three");
}
});
}
}
基于函數(shù)式路由
@Component
public class HelloWorldHandlerFunction {
public Mono<ServerResponse> hello(ServerRequest serverRequest) {
return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).body(
BodyInserters.fromValue("Hello World"));
}
}
@Configuration
public class HelloWorldRouter {
@Bean
public RouterFunction<ServerResponse> routeHelloWorld(HelloWorldHandlerFunction helloWorldHandlerFunction) {
return RouterFunctions.route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
helloWorldHandlerFunction::hello);
}
}