快速上手Spring WebFlux框架
一、前言
本文主要介绍基于SpringBoot如何快速上手使用SpringFlux框架开发WEB网站。
Spring 5.0在原有的Spring MVC Stack(又称Servlet Stack)以外,又引入了新的WEB开发技术栈——Spring Flux Stack(又称Reactive Stack),以满足不同的应用程序及开发团队的需求。
开发者一直在寻找最适合他们的应用程序的运行时、编程框架及架构。比如,有些用例最适合采用基于同步阻塞IO架构的技术栈,而另一些用例可能更适合于基于Reactive Streams响应式编程原则构建的异步的、非阻塞的技术栈。
后续将有系列文章深入介绍SpringFlux所采用的响应式编程原则及其代表实现ProjectReactor,希望通过系列文章的介绍,让广大读者能够在逐步使用SpringFlux的过程中,理解响应式编程原理及实现,进而能够对项目应该选择SpringMVC还是SpringWebFlux形成自己的判断标准。
二、快速上手
1、创建项目
打开 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等)。
2、增加一个Controller
如果你熟悉Spring MVC,你一定对@Controller注解不陌生。即使不熟悉也没关系,我会简单介绍一下。
Spring WebFlux带有两种特征,一种是函数式的(Functional),另一种是基于注解的(annotation-based)。函数式编程不太适合快速上手,我们先选择基于注解。类似于Spring MVC模型,Spring WebFlux模型也使用@Controller注解,以及@RestController注解。
用IDE打开项目后,追加一个类:SampleController
然后增加如下代码:
@RestController
@RequestMapping("/")
public class SampleController {@GetMapping("/hello")public String hello(){return "hello";}
}
运行后,用浏览器访问:http://localhost:8080/hello,将会在浏览器上看到"hello"字样。
怎么样,是不是很简单。
3、增加一个WebFilter
增加一个Filter试试看。在Spring WebFlux框架下,增加Filter是通过实现WebFilter接口实现的。
@Component
public class FirstWebFilter implements WebFilter {@Overridepublic Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {serverWebExchange.getAttributes().put("User", "jerry");return webFilterChain.filter(serverWebExchange);}
}
三、深入了解一下SpringBoot启动Spring WebFlux的过程
对于已经笔记熟悉Spring MVC框架的开发人员来说,快速上手无法满足欲望。必须了解其背后的机制原理等,方能有知己知彼的感觉。接下来稍微探讨以下SpringBoot启动Spring WebFlux的过程。尚不太熟悉Spring MVC框架的开发人员也可以阅读一下本章内容,或许对更好地使用Spring WebFlux框架有帮助。
1、准备工作
你需要从Gitubhttps://github.com/spring-projects/spring-framework下载Spring WebFlux的源码,以便进行后续分析。
2、@EnableWebFlux
回顾一下通过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 {@Beanpublic DispatcherHandler webHandler() {return new DispatcherHandler();}@Beanpublic 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;}
}
2、DispatcherHandler
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
- 映射Request到Handler
- HandlerMapping的默认实现是RequestMappingHandlerMapping,用于@RequestMapping所标记的方法;RouterFunctionMapping用于函数式端点的路由;SimpleUrlHandlerMapping用于显式注册的URL模式与WebHandler
HandlerAdaptor
- 帮助DispatcherHandler调用Request所映射的Handler
- HandlerAdaptor的主要作用是将DispatcherHandler从调用具体Handler的细节中解放出来
HandlerResultHandler
- 处理Handler的结果并终结Response
- 调用具体的Handler的返回结果是包装在HandlerResult中的,HandlerResultHandler负责处理HandlerResult。比如ResponseBodyResultHandler负责处理@ResponseBody标记的方法的返回值
示意图如下:
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处理请求的套路
- 先通过HandlerMapping找到Request的专用Handler,具体的代码片段是
concatMap(mapping -> mapping.getHandler(exchange))
- 再通过HandlerAdaptor执行这个具体的Handler,具体的代码片段是
flatMap(handler -> invokeHandler(exchange, handler))
- 最后通过HandlerResultHandler处理Handler返回的结果,具体的代码片段是
flatMap(result -> handleResult(exchange, result))
可能你有疑问,这个方法里Request在哪呢?藏在"ServerWebExchange exchange"里了,关于ServerWebExchange又其它文章进一步介绍,这儿就不作详细说明了。
3、HandlerMapping
DispatcherHandler套路中,处理Request的第一环节就是使用HandlerMapping。常见的HandlerMapping有三种:RequestMappingHandlerMapping、RouterFunctionMapping、SimpleUrlHandlerMapping
RequestMappingHandlerMapping是默认的,是否还记得DispatcherHandler中有发布一个Bean名为"requestMappingHandlerMapping"?它承担了映射Request与annotation-based Handler之间的关系。
由于我们习惯于使用@Controller、@RestController、@RequestMapping之类的注解来开发WEB项目,所以非常依赖RequestMappingHandlerMapping。我们接下来就谈谈RequestMappingHandlerMapping。
3-1、RequestMappingHandlerMapping的类层级
1层:AbstractHandlerMapping implements HandlerMapping, Ordered, BeanNameAware
^|
2层:AbstractHandlerMethodMapping implements InitializingBean
^|
3层:RequestMappingInfoHandlerMapping
^|
4层:RequestMappingHandlerMapping implements EmbeddedValueResolverAware
3-2、扫描可用handler
大家注意到,第2层实现了InitializingBean接口,实现了该接口的类有机会在BeanFactory设置好它的所有属性后通过调用
void afterPropertiesSet()
方法通知它。我们来看看第2层的对该方法的实现吧。
@Override
public void afterPropertiesSet() {initHandlerMethods();// Total includes detected mappings + explicit registrations via registerMapping.....
}
篇幅原因,这儿不细究方法中所调用的
initHandlerMethods();
的细节了 —— 实际上这里面是扫描所有@Controller注解的类中的@RequestMapping及其变体所修饰的方法,即最终会处理Request的Handler,并缓存起来,以便后续进一步执行。
3-3、与DispatcherHandler相互配合
DispatcherHandler会调用MappingHandler的
Mono<Object> getHandler(ServerWebExchange exchange)
方法,选择处理这个请求交的具体的Handler。
四、总结
Spring WebFlux模型的使用非常简单,尤其是对于熟悉Spring MVC模型的开发人员来说,无缝切换。使用Spring Boot框架开发时,使用@Controller、@RestController、@RequestMapping等注解,实现处理Request的Handler尤其方便。
原文:http://www.yesdata.net/2018/11/20/spring-flux/
快速上手Spring WebFlux框架相关推荐
- Spring WebFlux框架概述
Spring WebFlux框架概述 什么是 Spring WebFlux WebFlux 是Spring5添加的新模块,是一个使用响应式编程和异步非阻塞的Web开发框架,它的功能和 Spring M ...
- 5 分钟快速上手 pytest 测试框架
本文将会把关于 Pytest 的内容分上下两篇,上篇主要涉及关于 pytest 概念以及功能组件知识的介绍,下篇主要以一个 Web 项目来将 Pytest 运用实践中. 为什么要做单元测试 相信很多 ...
- 快速上手 Spring Boot 项目开发
1. 从零开始 Spring Boot 工程 Spring Boot 可以快速构建基于 Spring 框架的 JavaWeb 应用,快速整合包括视图层.MVC架构以及持久化层在内的各种框架,不需 ...
- Spring WebFlux框架 - WebFlux 配置
接上一篇博客:https://blog.csdn.net/qq_43605444/article/details/122420890?spm=1001.2014.3001.5502 11.WebFlu ...
- mockito mock void方法_一文让你快速上手 Mockito 单元测试框架
前言 在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用.为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多 ...
- mockito mock void方法_一文让你快速上手 Mockito 单元测试框架(上)
作者|mghio 编辑|包包 前言 在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用.为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改 ...
- 快速上手用Taro框架搭建一个微信小程序
1.安装node版本管理工具https://www.runoob.com/nodejs/nodejs-install-setup.html 2.打开终端 3.打开终端后在命令行输入npm instal ...
- 快速上手Spring--1.收集的一些资料
"好的开始是成功的一半",但凡一种新的技术,开始阶段一般是很苦恼的.为了不让更多的人走同样的弯路,我这里就把学习Spring的经验与大家分享, 一起快乐一下. Spring ...
- SpringBoot整合流行框架(上) 究其原理 去其糟粕 如何快速上手所有流行框架整合的方法一文足以~
最新文章
- 机器学习算法与技术简介
- 通过案例了解puppet创建虚拟资源解决资源冲突问题
- JBPM回退功能的实现
- 第八届蓝桥杯决赛 磁砖样式(枚举)
- oracle夜未眠之一增删改查
- linux串口传文件除了rz,使用sz/rz基于串口传输文件
- boost::prev_permutation相关的测试程序
- JS、javascript计算两个时间差
- python做的大型游戏_Python有做大型游戏的潜力吗?
- 使用Python实现生产者消费者问题
- 第二章节 变量与数据类型
- pclzip.lib.php,LimeSurvey
- 【mosek.fusion】Portfolio Optimization
- spring源码解析专栏导航
- HBuilderX连接安卓模拟器
- python程序文件默认扩展名_Python程序文件的扩展名是:
- 便捷缴费 支付 (一)
- 哈夫曼树中压缩率到底是什么意思
- 饥荒启动服务器显示error,Win10电脑运行饥荒游戏提示error during initialization解决方法...
- PDF文件不能编辑,有什么办法能够解决?
热门文章
- matlab动画_用matlab做一个脉动磁势分解的动画
- 20211205:力扣第270场周赛(上)
- 20190907:(leetcode习题)打家劫舍
- 三星s20计算机怎么添加到桌面,三星s20+怎么分屏?三星s20系列多窗口分屏设置操作步骤...
- LINUX PATH环境变量
- 波士顿动力十年对比刷屏,网友:以后该不会变成终结者吧?
- 幸好权健AI还没落地!一个腕表顶中医,18个关键点就能刷脸
- 美国签证过不了,ICLR 2020搬到埃塞俄比亚,同性恋学者:不去,保命要紧
- 手机照片脑补成超大画幅,这个GAN想象力惊人 | Keras实现
- 马上开始的机器学习顶会ICML该关注什么?论文集、精彩Workshop都在这里