本文主要介紹基於SpringBoot如何快速上手使用SpringFlux框架開發WEB網站。java
Spring 5.0在原有的Spring MVC Stack(又稱Servlet Stack)之外,又引入了新的WEB開發技術棧——Spring Flux Stack(又稱Reactive Stack),以知足不一樣的應用程序及開發團隊的需求。react
開發者一直在尋找最適合他們的應用程序的運行時、編程框架及架構。好比,有些用例最適合採用基於同步阻塞IO架構的技術棧,而 另外一些用例可能更適合於基於 Reactive Streams響應式編程原則構建的異步的、非阻塞的技術棧。
後續將有系列文章深刻介紹SpringFlux所採用的響應式編程原則及其表明實現ProjectReactor,但願經過系列文章的介紹,讓廣大讀者可以在逐步使用SpringFlux的過程當中,理解響應式編程原理及實現,進而可以對項目應該選擇SpringMVC仍是SpringWebFlux造成本身的判斷標準。git
文章系列github
<!-- more -->web
打開 http://start.spring.io,來初始化一個Spring WebFlux項目吧。左側一列是Project Metadata,填上你的group名(咱們使用net.yesdata吧),還有Artifact名(默認是demo);而後右側一列是Dependencies(依賴),咱們輸入"reactive web",在獲得的下拉框中選擇"Reacive Web",而後下方"Selected Dependencies"處會顯示咱們選中的"Reactive Web"。而後點擊"Generate Project",瀏覽器會下載建立好的Spring Boot項目。加壓後用你喜歡的IDE(Eclipse或者IntelliJ IDEA等)。spring
若是你熟悉Spring MVC,你必定對@Controller註解不陌生。即便不熟悉也不要緊,我會簡單介紹一下。
Spring WebFlux帶有兩種特徵,一種是函數式的(Functional),另外一種是基於註解的(annotation-based)。函數式編程不太適合快速上手,咱們先選擇基於註解。相似於Spring MVC模型,Spring WebFlux模型也使用@Controller註解,以及@RestController註解。編程
用IDE打開項目後,追加一個類:SampleController
而後增長以下代碼:segmentfault
@RestController @RequestMapping("/") public class SampleController { @GetMapping("/hello") public String hello(){ return "hello"; } }
運行後,用瀏覽器訪問:http://localhost:8080/hello,將會在瀏覽器上看到"hello"字樣。瀏覽器
怎麼樣,是否是很簡單。緩存
增長一個Filter試試看。在Spring WebFlux框架下,增長Filter是經過實現WebFilter接口實現的。
@Component public class FirstWebFilter implements WebFilter { @Override public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { serverWebExchange.getAttributes().put("User", "jerry"); return webFilterChain.filter(serverWebExchange); } }
對於已經筆記熟悉Spring MVC框架的開發人員來講,快速上手沒法知足慾望。必須瞭解其背後的機制原理等,方能有知己知彼的感受。接下來稍微探討如下SpringBoot啓動Spring WebFlux的過程。尚不太熟悉Spring MVC框架的開發人員也能夠閱讀一下本章內容,或許對更好地使用Spring WebFlux框架有幫助。
你須要從Gitubhttps://github.com/spring-projects/spring-framework下載Spring WebFlux的源碼,以便進行後續分析。
回顧一下經過http://start.spring.io建立項目中,DemoApplication啓動類的註解中,有一個註解是:@EnableWebFlux。SpringBoot就是經過這個註解,來啓動Spring WebFlux的。
@EnableWebFlux @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
再看一下EnableWebFlux的定義(能夠到SpringWebFlux源碼中找到),以下,咱們注意到它引入了DelegatingWebFluxConfiguration類。看來祕密會藏在DelegatingWebFluxConfiguration類裏呢。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(DelegatingWebFluxConfiguration.class) public @interface EnableWebFlux { }
打開DelegatingWebFluxConfiguration.java文件(能夠到SpringWebFlux源碼中找到),而後你咱們發現它的父類是WebFluxConfigurationSupport類。咱們先來看看這個父類。
@Configuration public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport { ...... }
下面是父類WebFluxConfigurationSupport實現的代碼片斷。咱們注意到,它向Spring Bean容器中,注入了兩個Bean:webHandler和requestMappingHandlerMapping(實際上還注入了其它若干個Bean,不過咱們暫時只關注這兩個吧)。
名爲"webHandler"的Bean的類型是DispatcherHandler,顧名思義是分發器,分發請求給各個處理單元。
名爲"requestMappingHandlerMapping"的Bean的類型是RequestMappingHandlerMapping,它的根本是實現了HandlerMapping接口。HandlerMapping的做用是將請求映射到Handler上,好比把某個請求路徑映射到某個Controller上。
關於DispatcherHandler和HandlerMapping,後面章節繼續深刻講解。
public class WebFluxConfigurationSupport implements ApplicationContextAware { @Bean public DispatcherHandler webHandler() { return new DispatcherHandler(); } @Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); mapping.setOrder(0); mapping.setContentTypeResolver(webFluxContentTypeResolver()); mapping.setCorsConfigurations(getCorsConfigurations()); PathMatchConfigurer configurer = getPathMatchConfigurer(); Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch(); if (useTrailingSlashMatch != null) { mapping.setUseTrailingSlashMatch(useTrailingSlashMatch); } Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch(); if (useCaseSensitiveMatch != null) { mapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch); } Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes(); if (pathPrefixes != null) { mapping.setPathPrefixes(pathPrefixes); } return mapping; } }
DispatcherHandler將自身做爲Bean註冊到Spring的Bean容器中,它與WebFilter、WebExceptionHandler等一塊兒,組成處理鏈。
DispatcherHandler會從Spring Configuration中探尋到它須要的組件,主要是如下三類:
public class DispatcherHandler implements WebHandler, ApplicationContextAware { ... private List<HandlerMapping> handlerMappings; private List<HandlerAdapter> handlerAdapters; private List<HandlerResultHandler> resultHandlers; ... }
HandlerMapping
HandlerAdaptor
HandlerResultHandler
示意圖以下:
DispatcherHandler | |-->HandlerMapping |-->HandlerAdaptor |-->HandlerResultHandler
DispatcherHandler的核心方法是:
@Override public Mono<Void> handle(ServerWebExchange exchange) { if (this.handlerMappings == null) { return Mono.error(HANDLER_NOT_FOUND_EXCEPTION); } return Flux.fromIterable(this.handlerMappings) .concatMap(mapping -> mapping.getHandler(exchange)) .next() .switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION)) .flatMap(handler -> invokeHandler(exchange, handler)) .flatMap(result -> handleResult(exchange, result)); }
該方法道出了DispatcherHandler處理請求的套路
concatMap(mapping -> mapping.getHandler(exchange))
flatMap(handler -> invokeHandler(exchange, handler))
flatMap(result -> handleResult(exchange, result))
可能你有疑問,這個方法裏Request在哪呢?藏在"ServerWebExchange exchange"裏了,關於ServerWebExchange又其它文章進一步介紹,這兒就不做詳細說明了。
DispatcherHandler套路中,處理Request的第一環節就是使用HandlerMapping。常見的HandlerMapping有三種:RequestMappingHandlerMapping、RouterFunctionMapping、SimpleUrlHandlerMapping
RequestMappingHandlerMapping是默認的,是否還記得DispatcherHandler中有發佈一個Bean名爲"requestMappingHandlerMapping"?它承擔了映射Request與annotation-based Handler之間的關係。
因爲咱們習慣於使用@Controller、@RestController、@RequestMapping之類的註解來開發WEB項目,因此很是依賴RequestMappingHandlerMapping。咱們接下來就談談RequestMappingHandlerMapping。
1層:AbstractHandlerMapping implements HandlerMapping, Ordered, BeanNameAware
^ |
2層:AbstractHandlerMethodMapping implements InitializingBean
^ |
3層:RequestMappingInfoHandlerMapping
^ |
4層:RequestMappingHandlerMapping implements EmbeddedValueResolverAware
你們注意到,第2層實現了InitializingBean接口,實現了該接口的類有機會在BeanFactory設置好它的全部屬性後經過調用
void afterPropertiesSet()
方法通知它。咱們來看看第2層的對該方法的實現吧。
@Override public void afterPropertiesSet() { initHandlerMethods(); // Total includes detected mappings + explicit registrations via registerMapping.. ... }
篇幅緣由,這兒不細究方法中所調用的
initHandlerMethods();
的細節了 —— 實際上這裏面是掃描全部@Controller註解的類中的@RequestMapping及其變體所修飾的方法,即最終會處理Request的Handler,並緩存起來,以便後續進一步執行。
DispatcherHandler會調用MappingHandler的
Mono<Object> getHandler(ServerWebExchange exchange)
方法,選擇處理這個請求交的具體的Handler。
Spring WebFlux模型的使用很是簡單,尤爲是對於熟悉Spring MVC模型的開發人員來講,無縫切換。使用Spring Boot框架開發時,使用@Controller、@RestController、@RequestMapping等註解,實現處理Request的Handler尤爲方便。