一、前言

本文主要介绍基于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等)。

通过start.spring.io创建reactive栈的项目

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"字样。

增加SampleController

SampleController执行结果

怎么样,是不是很简单。

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框架相关推荐

  1. Spring WebFlux框架概述

    Spring WebFlux框架概述 什么是 Spring WebFlux WebFlux 是Spring5添加的新模块,是一个使用响应式编程和异步非阻塞的Web开发框架,它的功能和 Spring M ...

  2. 5 分钟快速上手 pytest 测试框架

    本文将会把关于 Pytest 的内容分上下两篇,上篇主要涉及关于 pytest 概念以及功能组件知识的介绍,下篇主要以一个 Web 项目来将 Pytest 运用实践中. 为什么要做单元测试 相信很多 ...

  3. 快速上手 Spring Boot 项目开发

    1. 从零开始 Spring Boot 工程    Spring Boot 可以快速构建基于 Spring 框架的 JavaWeb 应用,快速整合包括视图层.MVC架构以及持久化层在内的各种框架,不需 ...

  4. Spring WebFlux框架 - WebFlux 配置

    接上一篇博客:https://blog.csdn.net/qq_43605444/article/details/122420890?spm=1001.2014.3001.5502 11.WebFlu ...

  5. mockito mock void方法_一文让你快速上手 Mockito 单元测试框架

    前言 在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用.为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多 ...

  6. mockito mock void方法_一文让你快速上手 Mockito 单元测试框架(上)

    作者|mghio 编辑|包包 前言  在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用.为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改 ...

  7. 快速上手用Taro框架搭建一个微信小程序

    1.安装node版本管理工具https://www.runoob.com/nodejs/nodejs-install-setup.html 2.打开终端 3.打开终端后在命令行输入npm instal ...

  8. 快速上手Spring--1.收集的一些资料

    "好的开始是成功的一半",但凡一种新的技术,开始阶段一般是很苦恼的.为了不让更多的人走同样的弯路,我这里就把学习Spring的经验与大家分享, 一起快乐一下.     Spring ...

  9. SpringBoot整合流行框架(上) 究其原理 去其糟粕 如何快速上手所有流行框架整合的方法一文足以~

最新文章

  1. 机器学习算法与技术简介
  2. 通过案例了解puppet创建虚拟资源解决资源冲突问题
  3. JBPM回退功能的实现
  4. 第八届蓝桥杯决赛 磁砖样式(枚举)
  5. oracle夜未眠之一增删改查
  6. linux串口传文件除了rz,使用sz/rz基于串口传输文件
  7. boost::prev_permutation相关的测试程序
  8. JS、javascript计算两个时间差
  9. python做的大型游戏_Python有做大型游戏的潜力吗?
  10. 使用Python实现生产者消费者问题
  11. 第二章节 变量与数据类型
  12. pclzip.lib.php,LimeSurvey
  13. 【mosek.fusion】Portfolio Optimization
  14. spring源码解析专栏导航
  15. HBuilderX连接安卓模拟器
  16. python程序文件默认扩展名_Python程序文件的扩展名是:
  17. 便捷缴费 支付 (一)
  18. 哈夫曼树中压缩率到底是什么意思
  19. 饥荒启动服务器显示error,Win10电脑运行饥荒游戏提示error during initialization解决方法...
  20. PDF文件不能编辑,有什么办法能够解决?

热门文章

  1. matlab动画_用matlab做一个脉动磁势分解的动画
  2. 20211205:力扣第270场周赛(上)
  3. 20190907:(leetcode习题)打家劫舍
  4. 三星s20计算机怎么添加到桌面,三星s20+怎么分屏?三星s20系列多窗口分屏设置操作步骤...
  5. LINUX PATH环境变量
  6. 波士顿动力十年对比刷屏,网友:以后该不会变成终结者吧?
  7. 幸好权健AI还没落地!一个腕表顶中医,18个关键点就能刷脸
  8. 美国签证过不了,ICLR 2020搬到埃塞俄比亚,同性恋学者:不去,保命要紧
  9. 手机照片脑补成超大画幅,这个GAN想象力惊人 | Keras实现
  10. 马上开始的机器学习顶会ICML该关注什么?论文集、精彩Workshop都在这里