本文主要介绍基于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尤为方便。