Spring WebFlux编写响应式Controller接口

2023-11-12

一、基本概念

传统的web框架包含spring和springMVC,用以构建Servlet API并在Servlet容器中运行,其本质上是阻塞和多线程的,每个连接使用一个线程,在处理请求时,将从线程池中提取一个工作线程来处理该请求,同时该请求处理线程被阻塞,直到工作线程完成为止。因此在请求量很大的情况下,阻塞web框架不能有效地扩展。

响应式web框架spring webFlux在spring5.0版本开始推出,它是完全非阻塞、支持响应式流,并且运行在netty,undertow和Servlet3.1以上的web容器中。响应式异步web框架可以实现用较少线程达到更高的可扩展性,通过应用被称为event looping的技术,每个线程都能够处理许多请求,使得每个连接的成本低。

在这里插入图片描述
在一个event loop中,一切皆为事件,其中包括请求与回调,当需要完成一个重要的操作时,event loop并行的为那个操作注册一个回调,然后它继续去处理其他事件。当操作完成后,它会被event loop视为一个event,对于请求也是一样的操作。这样异步web框架就能够使用更少的线程处理繁重的请求,实现更好的扩展性。

1、什么是响应式编程

在传统的命令式编程中,代码都是一条一条依次执行的,产生阻塞时就会造成资源的浪费。而响应式编程是函数式和声明式的,通过该数据流的pipeline或stream描述涉及的流程。响应式流处理数据时只要数据是可用的就进行处理,而不是需要将数据作为一个整体进行提供,使我们能够并行执行任务以获得更大的可伸缩性。

Java Streams和Reactive Streams的区别
Java流通常是同步的,同时只能处理有限数据集,它们本质上是使用函数式进行集合迭代的一种方式。
响应式流支持任何大小的数据集,包括无限数据集的异步处理,使实时处理数据成为了可能。

2、响应式流中的各个角色和关系

响应式流的规范可通过四个接口定义来概括:Publisher、Subscriber、Subscription和Processor。

Publisher为每一个Subscription的Subscriber生产数据,Publisher接口中有一个subscribe()方法,Subscriber通过这个方法可以订阅Publisher。

public interface Publisher<T>{
    void subscribe(Subscriber<? super T> subscriber);
}    

Subscriber一旦进行了订阅,就可以从Publisher中接收消息,这些消息都是通过Subscriber接口中的方法进行发送。

public interface Subscriber<T>{
    void onSubscribe(Subscribtion sub);
    void onNext(T item);
    void onError(Throwable ex);
    void onComplete();
}    

Subscriber调用onSubscribe()方法会收到第一个消息,当Publisher调用onSubscribe(),会通过一个Subscription对象将消息传递给Subscriber,Subscriber可以通过Subscription获取消息,也可以通过它取消订阅。
每一个Publisher发布的项目都会通过onNext()方法将数据传输到Subscriber,如果出现错误,onError()方法将被调用,如果数据发送完成,将会调用onComplete()方法来告诉Subscriber,发送结束。

public interface Subscription{
    // n 表明接收多少个数据
    void request(long n);
    // 取消订阅
    void cancel(); 
}

至于Processor,它连接了Subscriber和Publisher

public interface Processor<T,R> extends Subscriber<T>,Publisher<R>{}

二、Reactor简介

响应式编程是通过建立一个用于数据流通的管道,数据在这个管道中进行各种各样的处理,在管道的每个阶段,是不能知道哪一步操作被哪一个线程执行了的,它们可能在同一个线程也可能不是。

1、Mono与Flux

Mono和Flux是Reactor中的两个核心类,两者都是响应式流中Publisher的实现,Flux表示任意个数据项的管道,Mono表示至多一个数据项的管道。
从对象创建Mono或Flux
使用just()方法创建一个响应式流,例如使用5个String对象来创建一个Flux:

Flux<String> fruitFlux = Flux.just("Apple","Orange","Grape","Banana","Strawberry")
.delaySubscription(Duration.ofMillis(250))
.delayElements(Duration.ofMillis(500)));

通常情况下,Flux会尽可能快的发送数据,delayElements()可以将数据发送速度减慢,上例中为每0.5s发送一个数据,而delaySubscription()使Flux发送第一个数据时延迟,上例中为延迟0.25s。

Publisher有了,现在需要创建一个Subscriber来订阅这个Publisher,消费其中的数据:

fruitFlux.subscribe(f -> System.out.println("Here's some fruit:" + f));

subscribe()中的lambda表达式实际上是一个简写的创建java.util.Consumer对象。

从集合创建
Flux也可以从任何的集合创建,如Iterable或Java Stream,Flux的静态方法fromArray()就是将接收的数组转换为一个Flux,类似的还有fromIterable()方法和fromStream()方法。

合并Mono或者Flux
Flux有一个mergeWith()方法,可以将两个Flux进行合并。除此之外,还有一个zip()方法,与mergeWith()不同的是,zip()是一个静态的创建操作,它将两个Flux相对应的元素进行压缩合并,压缩后发送出来的每个项目都是包含两个对象的容器。
在这里插入图片描述
在这里插入图片描述
转换响应式数据
对于Flux或Mono,最常用的操作之一就是将流中的数据转换为其他类型,Reactor为此提供了map()和flatMap()方法,map()操作会创建一个Flux,该Flux在重新发布之前,按照给定函数对其接收的每个对象执行指定的转换,而flatMap()不是简单的将一个对象映射到另一个对象,而是将对象映射到一个新的Mono或Flux。
在这里插入图片描述

三、Spring WebFlux

1、简介

Spring WebFlux是构建在一个响应式HTTP API之上,与Servlet API没有关系,可以在任何非阻塞web容器上运行,包括Netty、Undertow等。下图是SpringMVC与 Spring WebFlux的异同:
在这里插入图片描述
引入依赖:

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

2、构建响应式Controller

Spring WebFlux 与 Spring MVC 使用相同的controller层注解,在许多方面与SpringMVC没有区别。不过Spring WebFlux的Controller方法通常接受并返回响应式类型,比如Mono或Flux,而不是域类型或集合。
一个响应式controller通常是一个端到端的响应式栈的顶端,包括controller、repository、database和任何可能位于两者之间的service返回的数据类型都是响应式类型。
在这里插入图片描述

@GetMapping("/recent")
public Flux<User> getUser(){
    return userService.getAll();
}

3、使用函数式编程模型编写API

Spring5引入了一个新的函数式编程模型来定义响应式API,这个新的编程模型更像是一个库,而不是一个框架,允许将请求映射到不同注解的处理代码。使用Spring的函数式编程模型编写API涉及四种主要类型:

  • RequestPredicate:声明将会被处理的请求类型;
  • RouteFunction:声明一个匹配的请求应该如何被路由到处理代码处,也就是RequestPredicate和处理代码的映射关系;
  • ServerRequest:表示HTTP请求,包括对头和正文信息的访问;
  • ServerResponse:表示HTTP响应,包括头和正文信息。
@Configuration
public class RouteFunctionConfig {
    @Bean
    public RouterFunction<?> helloRouteFunction(){
        return RouterFunctions.route(
                RequestPredicates.GET("/hello"),
                request -> ServerResponse.ok().body(Mono.just("Hello World!"), String.class));
    }
}

在上面的代码中,RequestPredicates.GET()方法声明了一个RequestPredicate,它与 /hello 路径的HTTP GET请求相匹配,request即ServerRequest参数,ServerResponse.ok()表示创建一个带有HTTP 200 的状态码,body表示响应的内容。

helloRouterFunction()方法声明了一个仅处理单一请求(/hello)的RouterFunction,但是如果需要处理不同类型的请求,不必编写另一个@Bean方法,只需要调用andRoute()来添加另一个RequestPredicate到函数的映射即可,例如:

@Bean
    public RouterFunction<?> helloRouteFunction(){
        return RouterFunctions.route(
                RequestPredicates.GET("/hello"),
                request -> ServerResponse.ok().body(Mono.just("Hello World!"), String.class))
                .andRoute(RequestPredicates.GET("/bye"),
                request -> ServerResponse.ok().body(Mono.just("See you!"), String.class));

不过,在实际应用中,通常是以一下形式来配置的:

@Configuration
public class RouteFunctionConfig {
    @Bean
    public RouterFunction<?> routerFunction(){
        return RouterFunctions.route(
                RequestPredicates.GET("/user"),
                this::getUser).andRoute(RequestPredicates.POST("/add/user"),this::addUser);
    }

    public Mono<ServerResponse> getUser(ServerRequest request){
        return ServerResponse.ok().body(Flux.just("tom"),String.class);
    }

    public Mono<ServerResponse> addUser(ServerRequest request){
        Mono<String> userName = request.bodyToMono(String.class);
        return ServerResponse.ok().body(Flux.just(userName + "add success"),String.class);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring WebFlux编写响应式Controller接口 的相关文章

随机推荐

  • 服务器记录到虚拟mac,Mac 模拟JSON数据

    一 使用Apache本地服务器 1 开启 sudo usr sbin apachectl start 在浏览器中输入 https localhost 页面显示 it works 2 其实本地apachec指向一个文件下 Library We
  • Mycat/Mysql主从复制搭建详解

    Mycat server 1 6 mysql 5 7 24 linux 工具下载地址 mycat mysql navivat 链接 https pan baidu com s 1KCmSgXYXs9O5vHMHIgnbAg 提取码 ukaq
  • java 操作ES 增删改查总结

    本实例框架采用 nutz ES 如果 您查找相关知识 请注意过滤不相干的信息 controller 层 package com test ownasset controller import java io File import java
  • centOS 6 服务管理与服务脚本

    服务管理与服务脚本 linux服务 服务管理与服务脚本 linux服务 服务启动过程详解 chkconfig命令 非独立服务与xinetd进程 一个特殊的服务脚本 服务启动过程详解 在开机启动过程中 我们计算机的各种服务也会按照配置信息启动
  • python 数据标准化

    def datastandard from sklearn import preprocessing import numpy as np x np array 1 1 2 2 0 0 0 1 1 print 原始数据为 n x print
  • 交换机上抓包

    1 常用交换机抓包方式 华为 华三 锐捷交换机一般使用packet capture命令可以进行抓包 Arista交换机通过在bash下 使用linux命令tcpdump进行抓包 Cisco nexus 抓包使用ethanalyze命令 具体
  • AS400银行核心系统开发中的技术总结--数据字典和枚举值

    数据字典和枚举值 在核心系统应用开发中 数据字典有举足轻重的作用 数据字典是对系统中所有字段的归纳抽象 需要规范同类字段的类型长度 方便定义和修改 但是 在过去的核心系统中 数据字典的理解往往也会有失误 常见的错误方法 是试图穷举定义所有可
  • Flink Client 使用技巧和心得(Flink on Zeppelin)

    Flink 链接Kafka 先建立catalog CREATE CATALOG flink hive WITH type hive default database imods hive conf dir home admin flink
  • 八个维度讲解秒杀系统架构分析与实战

    路人 Java充电社 2022 09 06 08 06 发表于上海 收录于合集 java充电社263个 大家好 我是路人 更多优质文章见个人博客 http itsoku com Java充电社 Java充电社 专注分享Java技术干货 包括
  • 最小熵原理

    种草很好的博文 苏剑林 2018 Apr 18 最小熵原理 一 无监督学习的原理 Blog post Retrieved from https spaces ac cn archives 5448 苏剑林 2018 Apr 24 最小熵原理
  • scrapy框架的使用

    1 什么是scrapy框架 文档地址 http scrapy chs readthedocs io zh CN 1 0 intro overview html 这个详细的文档地址 大家可以保存一下 之前的文章中也有一些链接大家可以保存下来方
  • 云计算中的存储基础知识

    物理存储方式 云计算中的三辆马车 计算 网络 存储 硬盘分为两种型态 机械硬盘 HDD 和固态硬盘 SSD 物理磁盘类型 SATA盘 串口硬盘 常用于个人电脑 物理磁盘类型 SAS盘 常用于服务器 物理磁盘类型 NL SAS盘 采用SAS磁
  • Doris-查询(三)

    目录 1 查询设置 1 1 增大内存 1 2 修改超时时间 1 3 查询重试和高可用 1 3 1 代码方式 1 3 2 JDBC Connector 1 3 3 ProxySQL 方式 2 简单查询 3 Join查询 3 1 Broadca
  • PyQT5播放音频

    最近自己写的一个软件需要在持续监测T box的信号强度值时 领导提出在信号低于阈值时给出警报或指示 之前的想法是在软件界面上加一个指示灯 但这样还是需要Tester去盯着屏幕 这样不友好 所以索性在通过声音的方式给出警示 这样就不用一直盯着
  • 基于sklearn的特征选择方法

    1 特征选择 我们主要关心以下几个问题 1 特征差异性 也就是一列特征值若几乎没有什么变化 那么这个特征对模型并没有什么作用 2 相关性大小 也就是该维特征与target的相互作用有多大 2 过滤法 1 方差判别 给定阈值 排除那些方差低于
  • GZ-2022034 物联网技术应用赛项赛题(Windows系统运行维护)

    任务书1 使用过程发现局域网内网络设备无法获取到有效IP 请配置DHCP服务分配的IP从172 16 工位号 150开始至172 16 工位号 200结束 并启用服务 使用路由器配置DHCP 在工作站计算机中使用DOS窗口测试服务器计算机8
  • exure9 秘钥_AxureRP9.0秘钥(持续更新)

    Axure RP 9 0 0 3717 3719 正式版 Axure Enterprise Edition Licensee Freecrackdownload com KEY 5vYpJgQZ431X G5kp6jpOO8Vi3TySCB
  • 嵌入式系统之linux系统编程---16 守护进程

    1 什么是守护进程 守护进程 守护进程运行在后台 不跟任何控制终端关联 2 怎么创建一个守护进程 有两个基本要求 a 守护进程必须作为 init 进程的子进程 b 守护进程不跟控制终端交互 创建守护进程的步骤 1 使用 fork 函数创建一
  • 百度云的sugar大屏模板1

    1 企业实时销售数据1 2 企业实时销售数据2 3 电商618大数据 4 实时数据分析 5 某平台智能监控系统
  • Spring WebFlux编写响应式Controller接口

    文章目录 一 基本概念 1 什么是响应式编程 2 响应式流中的各个角色和关系 二 Reactor简介 1 Mono与Flux 三 Spring WebFlux 1 简介 2 构建响应式Controller 3 使用函数式编程模型编写API