1、Spring Webflux介绍

The original web framework included in the Spring Framework, Spring Web MVC, was purpose built for the Servlet API and Servlet containers. The reactive stack, web framework, Spring WebFlux, was added later in version 5.0. It is fully non-blocking, supports Reactive Streams back pressure, and runs on servers such as Netty, Undertow, and Servlet 3.1+ containers.

Both web frameworks mirror the names of their source modules spring-webmvc and spring-webflux and co-exist side by side in the Spring Framework. Each module is optional. Applications may use one or the other module, or in some cases both — e.g. Spring MVC controllers with the reactive WebClient.

In addition to the web framework, Spring WebFlux also provides a WebClient for performing HTTP requests, a WebTestClient for testing web endpoints, and also client and server reactive, WebSocket support.

Spring Framework 中包含的原始 Web 框架 Spring Web MVC 是专门为 Servlet API 和 Servlet 容器构建的。响应式堆栈、Web 框架、Spring WebFlux 是后来在 5.0 版中添加的。它是完全非阻塞的,支持 Reactive Streams背压,并且可以在 Netty、Undertow 和 Servlet 3.1+ 容器等服务器上运行。

这两个 Web 框架都反映了它们的源模块 spring-webmvc和 spring-webflux的名称, 并在 Spring 框架中并存。每个模块都是可选的。应用程序可以使用一个或另一个模块,或者在某些情况下两者都使用——例如带有响应式的 Spring MVC 控制器WebClient

除了 Web 框架之外,Spring WebFlux 还提供了一个用于执行 HTTP 请求的WebClientWebTestClient 、一个用于测试 Web 端点,以及客户端和服务器响应式 WebSocket 支持。

Web on Reactive Stack

2、响应式

The term "reactive" refers to programming models that are built around reacting to change — network component reacting to I/O events, UI controller reacting to mouse events, etc. In that sense non-blocking is reactive because instead of being blocked we are now in the mode of reacting to notifications as operations complete or data becomes available.

There is also another important mechanism that we on the Spring team associate with "reactive" and that is non-blocking back pressure. In synchronous, imperative code, blocking calls serve as a natural form of back pressure that forces the caller to wait. In non-blocking code it becomes important to control the rate of events so that a fast producer does not overwhelm its destination.

Reactive Streams is a small spec, also adopted in Java 9, that defines the interaction between asynchronous components with back pressure. For example a data repository — acting as Publisher, can produce data that an HTTP server — acting as Subscriber, can then write to the response. The main purpose of Reactive Streams is to allow the subscriber to control how fast or how slow the publisher will produce data.

响应式指的是围绕对变化做出反应而构建的编程模型——网络组件对 I/O 事件做出反应,UI 控制器对鼠标事件做出反应等。从这个意义上说,非阻塞是响应式的,因为我们不是被阻塞而是被阻塞现在处于操作完成或数据可用时对通知做出反应的模式。

我们在 Spring 团队中还有另一个与“响应式”相关的重要机制,那就是非阻塞背压。在同步的命令式代码中,阻塞调用是一种自然的背压形式,迫使调用者等待。在非阻塞代码中,控制事件的速率变得很重要,这样快速的生产者就不会压倒它的目的地。

Reactive Streams 是一个 小型规范,也在Java 9 中采用,它定义了具有背压的异步组件之间的交互。例如,作为 Publisher的数据存储库可以生成作为 订阅者的 HTTP 服务器然后可以写入响应的数据。Reactive Streams 的主要目的是允许订阅者控制发布者生成数据的速度或速度。

2.1 响应式API

Reactive Streams  --> Java8 Stream API

Reactor是spring webflux的首选响应式库(官方推荐)。它提供Mono(0-1个数据序列)和Flux(0-N个数据序列) API类型来处理数据序列。Reactor是一个Reactive Streams库,因此它的所有操作符都是支持非阻塞背压

2.2 编程模型

The spring-web module contains the reactive foundation that underlies Spring WebFlux — HTTP abstractions, Reactive Streams server adapters, reactive codecs, and a core Web API whose role is comparable to the Servlet API but with non-blocking semantics.

spring-web模块包含作为 Spring WebFlux 基础的响应式基础——HTTP 抽象、响应式流服务器适配器、响应式编解码器和一个核心 Web API,其作用与 Servlet API 相当,但具有非阻塞语义。

两种编程模型:

1)Annotated Controllers ——与 Spring MVC 一致,并基于spring-web模块中的相同注释。Spring MVC 和 WebFlux 控制器都支持响应式(Reactor、RxJava)返回类型,因此很难区分它们。一个显着的区别是 WebFlux 还支持响应式@RequestBody参数。

2)Functional Endpoints ——基于 lambda 的轻量级函数式编程模型。可以将其视为应用程序可以用来路由和处理请求的小型库或一组实用程序。带注释的控制器的最大区别在于,应用程序负责从头到尾处理请求,而不是通过注释声明意图并被回调。

2.3 选择Web框架

use Spring MVC or WebFlux?

1、如果您有一个运行良好(资源充足)的 Spring MVC 应用程序,则无需更改。命令式编程是编写、理解和调试代码的最简单方法。由于历史上大多数库都是阻塞的,因此您可以选择最多的库。

2、如果需要在有限的资源支持更多的请求,则可以选择webflux,支持更高的并发。标语是“用更少的硬件进行扩展”。 "scale with less hardware"

2.4 选择服务器

Netty、Undertow、Tomcat、Jetty 和 Servlet 3.1+ 容器支持 Spring WebFlux。每个服务器都适用于一个通用的 Reactive Streams API。Spring WebFlux 编程模型建立在该通用 API 之上。默认是Netty作为服务器(NIO)

2.5 性能与规模

性能有很多特点和含义。反应式和非阻塞通常不会使应用程序运行得更快。在某些情况下,它们可以,例如,如果使用 WebClient并行执行远程调用。总的来说,它需要更多的工作来以非阻塞方式做事,这可能会略微增加所需的处理时间。

反应式和非阻塞式的主要预期好处是能够使用少量固定数量的线程和更少的内存进行扩展。这使得应用程序在负载下更具弹性,因为它们以更可预测的方式扩展。然而,为了观察这些好处,您需要有一些延迟,包括混合缓慢和不可预测的网络 I/O。这就是反应式堆栈开始显示其优势的地方,并且差异可能是巨大的。

3、响应式Spring Web

The spring-web module provides low level infrastructure and HTTP abstractions — client and server, to build reactive web applications. All public APIs are build around Reactive Streams with Reactor as a backing implementation.

Server support is organized in two layers:

  • HttpHandler and server adapters — the most basic, common API for HTTP request handling with Reactive Streams back pressure.

  • WebHandler API — slightly higher level but still general purpose server web API with filter chain style processing.

spring-web模块提供低级基础设施和 HTTP 抽象——客户端和服务器,以构建响应式 Web 应用程序。所有公共 API 都是围绕 Reactive Streams 构建的,并以 Reactor 作为支持实现。

服务器支持分为两层:

  • HttpHandler和服务器适配器 — 用于使用 Reactive Streams 背压处理 HTTP 请求的最基本、最常用的 API。

  • WebHandler API  — 稍高一些,但仍然是具有过滤器链样式处理的通用服务器 Web API。

3.1 HttpHandler

每个 HTTP 服务器都有一些用于 HTTP 请求处理的 API。 HttpHandler 是一个简单的契约,它使用一种方法来处理请求和响应。它是故意最小的。它的主要目的是为不同服务器上的 HTTP 请求处理提供一个通用的、基于 Rective Streams 的 API。

Server name Server API used Reactive Streams support

Netty

Netty API

Reactor Netty

Undertow

Undertow API

spring-web: Undertow to Reactive Streams bridge

Tomcat

Servlet 3.1 non-blocking I/O; Tomcat API to read and write ByteBuffers vs byte[]

spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge

Jetty

Servlet 3.1 non-blocking I/O; Jetty API to write ByteBuffers vs byte[]

spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge

Servlet 3.1 container

Servlet 3.1 non-blocking I/O

spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge

依赖:

Server name Group id Artifact name

Reactor Netty

io.projectreactor.ipc

reactor-netty

Undertow

io.undertow

undertow-core

Tomcat

org.apache.tomcat.embed

tomcat-embed-core

Jetty

org.eclipse.jetty

jetty-server, jetty-servlet

4、Annotated Controllers

@RestController
public class HelloController {@GetMapping("/hello")public String handle() {return "Hello WebFlux";}
}

跟springmvc一致。

还有 HTTP 方法特定的快捷方式变体@RequestMapping

  • @GetMapping

  • @PostMapping

  • @PutMapping

  • @DeleteMapping

  • @PatchMapping

@RestController
@RequestMapping("/persons")
class PersonController {@GetMapping("/{id}")public Person getPerson(@PathVariable Long id) {// ...}@PostMapping@ResponseStatus(HttpStatus.CREATED)public void add(@RequestBody Person person) {// ...}
}

您还可以声明 URI 变量并使用以下命令访问它们的值@PathVariable

@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {// ...
}
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;public class PersonHandler {private final PersonRepository repository;public PersonHandler(PersonRepository repository) {this.repository = repository;}public Mono<ServerResponse> listPeople(ServerRequest request) { Flux<Person> people = repository.allPeople();return ServerResponse.ok().contentType(APPLICATION_JSON).body(people, Person.class);}public Mono<ServerResponse> createPerson(ServerRequest request) { Mono<Person> person = request.bodyToMono(Person.class);return ServerResponse.ok().build(repository.savePerson(person));}public Mono<ServerResponse> getPerson(ServerRequest request) { int personId = Integer.valueOf(request.pathVariable("id"));Mono<ServerResponse> notFound = ServerResponse.notFound().build();Mono<Person> personMono = this.repository.getPerson(personId);return personMono.flatMap(person -> ServerResponse.ok().contentType(APPLICATION_JSON).body(fromObject(person))).switchIfEmpty(notFound);}
}

listPeople是一个处理函数,它Person以 JSON 形式返回在存储库中找到的所有对象。
createPerson是一个处理函数,用于存储Person请求正文中包含的新内容。
请注意,PersonRepository.savePerson(Person)返回Mono<Void>:一个空的 Mono,
当从请求中读取并存储人员时发出完成信号。因此,我们使用该 build(Publisher<Void>)
方法在接收到完成信号时发送响应,即当Person已保存时。
getPerson是一个处理函数,它返回一个人,通过路径变量标识id。
我们Person通过存储库检索它,并在找到它时创建一个 JSON 响应。
如果未找到,我们使用switchIfEmpty(Mono<T>)返回 404 Not Found 响应。

5、路由功能

RouterFunction<ServerResponse> helloWorldRoute =RouterFunctions.route(RequestPredicates.path("/hello-world"),request -> Response.ok().body(fromObject("Hello World")));RouterFunction<ServerResponse> personRoute =route(GET("/person/{id}").and(accept(APPLICATION_JSON)), handler::getPerson).andRoute(GET("/person").and(accept(APPLICATION_JSON)), handler::listPeople).andRoute(POST("/person").and(contentType(APPLICATION_JSON)), handler::createPerson);

6、处理程序过滤函数

import static org.springframework.http.HttpStatus.UNAUTHORIZED;SecurityManager securityManager = ...
RouterFunction<ServerResponse> route = ...RouterFunction<ServerResponse> filteredRoute =route.filter(request, next) -> {if (securityManager.allowAccessTo(request.path())) {return next.handle(request);}else {return ServerResponse.status(UNAUTHORIZED).build();}});

7、WebFlux Java 配置

默认情况下,安装了NumberDate类型的格式化程序,包括对@NumberFormat@DateTimeFormat注释的支持。如果类路径中存在 Joda Time,则还安装了对 Joda Time 格式化库的完全支持。

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {@Overridepublic void addFormatters(FormatterRegistry registry) {// ...}
}

7.1 验证

如果Bean Validation存在于类路径中——例如 Hibernate Validator,则将LocalValidatorFactoryBean其注册为全局Validator ,以便与方法参数一起使用@ValidValidated在 @Controller方法参数上使用。

在Java 配置中,可以自定义全局Validator实例:

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {@Overridepublic Validator getValidator(); {// ...}}

Spring提供了@initBinder(初始化绑定封装)注解和WebDataBinder工具。用户只需要向WebDataBinder注册自己需要的类型的属性编辑器即可。

@Controller
public class MyController {@InitBinderprotected void initBinder(WebDataBinder binder) {binder.addValidators(new FooValidator());}}

7.2 内容类型解析器 Content type resolvers

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {@Overridepublic void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {// ...}
}

7.3 HTTP消息编解码器

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {@Overridepublic void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {// ...}
}

7.4  View resolvers

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {// ...}@Beanpublic FreeMarkerConfigurer freeMarkerConfigurer() {FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();configurer.setTemplateLoaderPath("classpath:/templates");return configurer;}
}

7.5 静态资源

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/resources/**").addResourceLocations("/public", "classpath:/static/").setCachePeriod(31556926);}}
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/resources/**").addResourceLocations("/public/").resourceChain(true).addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));}}

可以使用ResourceUrlProvider重写 URL 并应用完整的解析器和转换器链——例如插入版本。WebFlux 配置提供了一个ResourceUrlProvider ,因此可以将其注入其他人。

7.6 路径匹配

Spring WebFlux 使用路径模式的解析表示——即PathPattern,以及传入的请求路径——即RequestPath,这消除了指示是否解码请求路径或删除分号内容的需要,因为PathPattern 现在可以访问解码的路径段值并安全地匹配。

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {// ...}}

7.7 Retrieve

    ​WebClient client = WebClient.create("http://example.org");​Mono<Person> result = client.get()​.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)​.retrieve()​.bodyToMono(Person.class);
​Flux<Quote> result = client.get()​.uri("/quotes").accept(TEXT_EVENT_STREAM)​.retrieve()​.bodyToFlux(Quote.class)

7.8 Exchange

Mono<Person> result = client.get().uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON).exchange().flatMap(response -> response.bodyToMono(Person.class));
Mono<ResponseEntity<Person>> result = client.get().uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON).exchange().flatMap(response -> response.bodyToEntity(Person.class));

7.9 Request body

ono<Person> personMono = ... ;Mono<Void> result = client.post().uri("/persons/{id}", id).contentType(MediaType.APPLICATION_JSON).body(personMono, Person.class).retrieve().bodyToMono(Void.class);lux<Person> personFlux = ... ;Mono<Void> result = client.post().uri("/persons/{id}", id).contentType(MediaType.APPLICATION_STREAM_JSON).body(personFlux, Person.class).retrieve().bodyToMono(Void.class);Person person = ... ;Mono<Void> result = client.post().uri("/persons/{id}", id).contentType(MediaType.APPLICATION_JSON).syncBody(person).retrieve().bodyToMono(Void.class);

7.10 Builder options

 SslContext sslContext = ...ClientHttpConnector connector = new ReactorClientHttpConnector(builder -> builder.sslContext(sslContext));WebClient webClient = WebClient.builder().clientConnector(connector).build();ExchangeStrategies strategies = ExchangeStrategies.builder().codecs(configurer -> {// ...}).build();WebClient webClient = WebClient.builder().exchangeStrategies(strategies).build();

7.11 过滤器

 WebClient client = WebClient.builder().filter((request, next) -> {ClientRequest filtered = ClientRequest.from(request).header("foo", "bar").build();return next.exchange(filtered);}).build();WebClient client = WebClient.builder().filter(basicAuthentication("user", "pwd")).build();WebClient filteredClient = client.mutate().filter(basicAuthentication("user", "pwd").build();

7.12 Reactive Libraries

Reactor 是spring-webflux模块必需的依赖项,在内部用于编写逻辑和支持 Reactive Streams。一个容易记住的规则是 WebFlux API 返回FluxMono - 因为这是内部使用的,并且宽松地接受任何 Reactive StreamsPublisher实现。

使用FluxandMono有助于表达基数——例如,是否需要单个或多个异步值。这对于 API 设计很重要,但在某些情况下也很重要,例如在编码 HTTP 消息时。

对于带注释的控制器,WebFlux 透明地适应使用的反应库,并正确转换基数。这是在 ReactiveAdapterRegistry的 帮助下完成的,spring-core它提供了对反应和异步类型的可插入支持。注册表内置了对 RxJava 的支持,CompletableFuture但也可以注册其他注册表。

对于功能性端点、WebClient. 和其他功能性 API,WebFlux API 的一般经验法则适用:

  • FluxMono作为返回值——使用它们来组成逻辑或传递给任何 Reactive Streams 库(两者都是Publisher实现)。

  • Publisher用于输入的反应式流——如果提供了Publisher来自另一个反应式库的 a,它只能被视为具有未知语义 (0..N) 的流。如果语义是已知的——例如io.reactivex.Single,您可以使用Mono.from(Publisher)并传递它而不是原始的Publisher

Spring Webflux简介相关推荐

  1. corda_使用Spring WebFlux从Corda节点流式传输数据

    corda 自上次发布以来已经有一段时间了,但我终于回来了! 由于我仍在我的项目中,因此我将再次撰写有关使用Corda的文章. 这次,我们将不再关注Corda,而是将Spring与Corda结合使用. ...

  2. 使用Spring WebFlux从Corda节点流式传输数据

    自上次发布以来已经有一段时间了,但我终于回来了! 由于我仍在我的项目中,因此我将再次撰写有关使用Corda的文章. 这次,我们将不再关注Corda,而是将Spring与Corda结合使用. 更具体地说 ...

  3. Spring Boot 3.x 系列【23】集成Spring WebFlux开发响应式应用程序

    有道无术,术尚可求,有术无道,止于术. 本系列Spring Boot版本3.0.4 源码地址:https://gitee.com/pearl-organization/study-spring-boo ...

  4. 响应式编程之Spring Webflux

    文章目录 一 .响应式编程 二 .响应式流 (1)JDK9响应式流: (2)Reactor响应式流库 三.Spring WebFlux 1.整合Webflux 2.事件推送 3.实现背压 四.配置数据 ...

  5. Spring WebFlux 实践

    文章目录 WebFlux 学习之路 1 .WebFlux 简介 2.WebFlux 的数据库操作 WebFlux 实践内容 1 .入门案例 1.1 RouterConfiguration 1.2 Ro ...

  6. 爸爸又给Spring MVC生了个弟弟叫Spring WebFlux

    作者:李新杰 来自:编程新说 情景引入 很早之前,Java就火起来了,是因为它善于开发和处理网络方面的应用. Java有一个爱好,就是喜欢制定规范标准,但自己又不善于去实现. 反倒是一些服务提供商使用 ...

  7. Spring入门简介

    Spring概况 Spring的简介 Spring是一个轻量级的控制反转和面向切面的容器框架,它主要是为了解决企业应用开发的复杂性而诞生的: 目的:解决企业应用开发的复杂性 功能:使用基本的javaB ...

  8. Spring Webflux: Kotlin DSL [片断]

    原文链接:https://dzone.com/articles/spring-webflux-kotlin-dsl-snippets 作者:Biju Kunjummen 译者:Jackie Tang ...

  9. Spring WebFlux和Spring Cloud开发响应式微服务

    作者:Piotr Mińkowski 译者:大萝卜爱上小白菜 原文:https://dzone.com/articles/reactive-microservices-with-spring-webf ...

最新文章

  1. 小米6鲁大师html5评测,一加6T依然是顶级旗舰!鲁大师2018手机性能榜跑分排前三!...
  2. 基于单片机的水壶自动加热系统_基于烟雾检测火灾自动报警系统
  3. 20110609 搭域控,布线,设计网络,杂事一堆啊
  4. antd table设置表格一个单元格的字体颜色_微软Office三件套,各有一个效率神器,全都知道的人不超过1%...
  5. BZOJ 1293 [SCOI2009]生日礼物
  6. handler原子锁_深入Linux内核架构——锁与进程间通信
  7. 动画,视频处理的计算机系统,音视频与动画处理.ppt
  8. 语言取10的整数倍_C语言结构体用法很多,坑也很多
  9. react报Maximum update depth exceeded
  10. 一个公式来说明加接圈的作用和缺点
  11. 怎样增加phpmyadmin导入文件上限
  12. 日记 [2008年01月05日]NTP 服务器
  13. exfat文件系统相关数据结构以及数据恢复方法
  14. hex2bin 64bit
  15. html js禁止跳转页面,js 控制页面跳转的5种方法
  16. EXCEL中文转英文首字母拼写
  17. php数据库操作类库doctrine使用全攻略
  18. QT 自学内容 day03 listWidget ,treeWidget,tableWidget ,stackedWidget,模态,和非模态 多种 对话框的的使用
  19. [Android开发] Xposed 插件开发之一: Xposed入门
  20. 从键盘输入一个三位整数n,分别求出n的个位数字、十位数字和百位数字

热门文章

  1. android beam苹果,安卓多年黑科技 苹果终于蹒跚追上_苹果 iPhone X _手机评测-中关村在线...
  2. 设计模式Part3——简单工厂模式
  3. 视频云计算在NGB中应用的探讨
  4. 一文教会你离线Linux主机简易搭建YUM源私服
  5. 2015年北京师范大学新生程序设计竞赛题解
  6. photoshop手绘教程:水墨风格美女
  7. Linux批量结束进程命令
  8. 计算机专业中端学生笔记本电脑,2021学生党高性价比的电脑推荐
  9. 分析目标客户,你都Get到了吗?
  10. 性能测试_JMeter中你可能会忽略的细节点-2