Spring WebFlux

文章目录

  • 一、概述
    • 1、Spring体系定位
    • 2、Spring MVC和WebFlux差异
  • 二、入门
    • 1、依赖
    • 2、ReactorHttpHandlerAdapter(main启动)
    • 3、DispatcherHandler(SpringWebFlux启动)
    • 4、WebFilter
  • 三、DispatcherHandler理解
    • 1、handle

前置知识(很重要):Reactive Streams&Reactor Core

一、概述

官网地址

1、Spring体系定位

我们不难发现整个响应式编程和传统的Servlet API属于两套完全不同但是又并行的技术栈,所以如果老项目想要改造为响应式编程,项目改造的成本很大

2、Spring MVC和WebFlux差异

1)技术栈体系上:

在声明接口处理上,如果是使用注解的形式,那么两边可以复用。具体到业务代码的处理写法上,必定涉及到不小的改造。

2)执行流程上:




二、入门

1、依赖

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

2、ReactorHttpHandlerAdapter(main启动)

服务端代码:

@SneakyThrows
public static void main(String[] args) {
    HttpHandler handler = (ServerHttpRequest request, ServerHttpResponse response) -> {
        URI uri = request.getURI();
        System.out.println(Thread.currentThread() + "接收请求:" + uri);
        request.getHeaders(); //获取请求头

        //数据的发布者:Mono<DataBuffer>、Flux<DataBuffer>

        // 1、创建响应数据的DataBuffer
        DataBufferFactory factory = response.bufferFactory();
        // 2、数据写入Buffer
        DataBuffer buffer = factory.wrap((uri + " ==> Hand success").getBytes());
        // 3、构建DataBuffer的发布者
        return response.writeWith(Mono.just(buffer));
    };

    // 启动一个服务器,监听8080端口,接受数据,拿到数据交给 HttpHandler 进行请求处理
    ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
    
    // 使用HttpServer启动Netty服务器
    HttpServer.create()
            .host("localhost")
            .port(8080)
            .handle(adapter)
            .bindNow();

    System.out.println("start success");
    System.in.read();
}

浏览器请求:

控制台返回:

3、DispatcherHandler(SpringWebFlux启动)

服务端代码,注意点:

  1. 涉及Http调用时,不要再使用RestTemplate发起,而是需要替换为WebClient处理
  2. 如果接口需要支持服务端推送的效果,需要设置produces为MediaType.TEXT_EVENT_STREAM_VALUE(text/event-stream)
public class TestController {

    @RequestMapping("/test")
    public String test() {
        System.out.println("http request test");
        return "test";
    }

    @GetMapping(value = "/test2", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Tuple2<Long, String>> test2() {
        WebClient webClient = WebClient.create("http://localhost:20888");
        return webClient.post()
                .uri("test")
                .retrieve()
                .bodyToFlux(String.class)
                .delayElements(Duration.ofSeconds(1)).index();
    }

    @GetMapping(value = "/test3", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Tuple2<Long, Integer>> test3() {
        return Flux.range(1, 3)
                .delayElements(Duration.ofSeconds(1))
                .timestamp();
    }
}

访问接口:

http://127.0.0.1:20888/test2

浏览器效果:

控制台:


访问接口:

http://127.0.0.1:20888/test3

4、WebFilter

由于webFlux使用的是Netty服务器,所以无法再使用Tomcat中Servlet规范下的Filter,此时我们需要借助Spring-web的org.springframework.web.server.WebFilter来处理我们的Filter逻辑

@Component
public class TestWebFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return Mono.defer(() -> {
            ServerHttpRequest request = exchange.getRequest();
            System.out.println("TestWebFilter: " + request.getPath());
            return chain.filter(exchange);
        });
    }
}




三、DispatcherHandler理解

1、handle

类比Spring MVC中DispatcherServlet#doDispatch方法

Spring WebFlux底提供了NettyWebServer,程序启动时,会调用NettyWebServer的startHttpServer(),并且给HttpServer绑定一个ReactorHttpHandlerAdapter,它包装了一个HttpHandler,ReactorHttpHandlerAdapter从Reactor-Netty-Http收到Request和Response对象后,就会传递给HttpHandler进行处理,HttpHandler链路依次为:

  1. ReactorHttpHandlerAdapter内部实际会委托DelayedInitializationHttpHandler进行处理
  2. 再次向下委托到HttpWebHandlerAdapter,会它负责将Request和Response包装生成一个ServerWebExchange对象,后面Handler接收到的都是ServerWebExchange对象
  3. 再次委托ExceptionHandlingWebHandler(可作用于异常隔离)
  4. 再次委托FilteringWebHandler(内部有一个chain用于存放我们创建的WebFilter)
  5. 最后,委托了DispatcherHandler,DispatcherHandler会根据当前请求,找到Controller中对应的方法。从而得到Mono或Flux
public Mono<Void> handle(ServerWebExchange exchange) { 
    if (this.handlerMappings == null) {
        return createNotFoundError();
    }
    // 跨域问题处理
    if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
        return handlePreFlight(exchange);
    }
    //拿到所有的 handlerMappings
    return Flux.fromIterable(this.handlerMappings) 
            // 找每一个mapping看谁能处理请求    
            .concatMap(mapping -> mapping.getHandler(exchange)) 
            // 直接触发获取元素; 拿到流的第一个元素; 找到第一个能处理这个请求的handlerAdapter
            .next() 
            // 如果没拿到这个元素,则响应404错误;
            .switchIfEmpty(createNotFoundError()) 
            // 异常处理,一旦前面发生异常,调用处理异常
            .onErrorResume(ex -> handleDispatchError(exchange, ex)) 
            // 调用方法处理请求,得到响应结果
            .flatMap(handler -> handleRequestWith(exchange, handler)); 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/956194.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM的自助购药小程序设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

Oracle graph 图数据库体验-安装篇

服务端安装 环境准备 安装数据库 DOCKER 安装23AI FREE &#xff0c;参考&#xff1a; https://container-registry.oracle.com/ords/f?p113:4:111381387896144:::4:P4_REPOSITORY,AI_REPOSITORY,AI_REPOSITORY_NAME,P4_REPOSITORY_NAME,P4_EULA_ID,P4_BUSINESS_AREA_ID:1…

CSS 的基础知识及应用

前言 CSS&#xff08;层叠样式表&#xff09;是网页设计和开发中不可或缺的一部分。它用于描述网页的视觉表现&#xff0c;使页面不仅实现功能&#xff0c;还能提供吸引人的用户体验。本文将介绍 CSS 的基本概念、语法、选择器及其在提升网页美观性方面的重要性。 什么是 CSS&…

C语言之装甲车库车辆动态监控辅助记录系统

&#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 C语言之装甲车库车辆动态监控辅助记录系统 目录 一、前言 1.1 &#xff08;一&#xff09;…

python+django+Nacos实现配置动态更新-集中管理配置(实现mysql配置动态读取及动态更新)

一、docker-compose.yml 部署nacos服务 version: "3" services:mysql:container_name: mysql# 5.7image: mysql:5.7environment:# mysql root用户密码MYSQL_ROOT_PASSWORD: rootTZ: Asia/Shanghai# 初始化数据库(后续的初始化sql会在这个库执行)MYSQL_DATABASE: nac…

OpenEuler学习笔记(一):常见命令

OpenEuler是一个开源操作系统&#xff0c;有许多命令可以用于系统管理、软件安装、文件操作等诸多方面。以下是一些常见的命令&#xff1a; 一、系统信息查看命令 uname 用途&#xff1a;用于打印当前系统相关信息&#xff0c;如内核名称、主机名、内核版本等。示例&#xff…

聊聊如何实现Android 放大镜效果

一、前言 很久没有更新Android 原生技术内容了&#xff0c;前些年一直在做跨端方向开发&#xff0c;最近换工作用重新回到原生技术&#xff0c;又回到了熟悉但有些生疏的环境&#xff0c;真是感慨万分。 近期也是因为准备做地图交互相关的需求&#xff0c;功能非常复杂&#x…

C++,设计模式,【目录篇】

文章目录 1. 简介2. 设计模式的分类2.1 创建型模式&#xff08;Creational Patterns&#xff09;&#xff1a;2.2 结构型模式&#xff08;Structural Patterns&#xff09;&#xff1a;2.3 行为型模式&#xff08;Behavioral Patterns&#xff09;&#xff1a; 3. 使用设计模式…

RabbitMQ集群安装rabbitmq_delayed_message_exchange

1、单节点安装rabbitmq安装延迟队列 安装延迟队列rabbitmq_delayed_message_exchange可以参考这个文章&#xff1a; rabbitmq安装延迟队列-CSDN博客 2、集群安装rabbitmq_delayed_message_exchange 在第二个节点 join_cluster 之后&#xff0c;start_app 就会报错了 (CaseC…

【C++】如何从源代码编译红色警戒2地图编辑器

【C】如何从源代码编译红色警戒2地图编辑器 操作视频视频中的代码不需要下载三方库&#xff0c;已经包含三方库。 一、运行效果&#xff1a;二、源代码来源及编程语言&#xff1a;三、环境搭建&#xff1a;安装红警2安装VS2022下载代码&#xff0c;源代码其实不太多&#xff0c…

下定决心不去读研了。。。

大家好&#xff0c;我是苍何。 之前发表过一篇文章&#xff0c;表达了自己读研的困惑和纠结&#xff0c;得到了大家很多的建议&#xff0c;也引起了很多人的共鸣&#xff0c;在留言区分享了自己的故事&#xff0c;看着这些故事&#xff0c;我觉得都够苍何写一部小说了。 可惜苍…

重温STM32之环境安装

缩写 CMSIS&#xff1a;common microcontroller software interface standard 1&#xff0c;keil mdk安装 链接 Keil Product Downloads 安装好后&#xff0c;开始安装平台软件支持包&#xff08;keil 5后不在默认支持所有的平台软件开发包&#xff0c;需要自行下载&#…

[苍穹外卖] 1-项目介绍及环境搭建

项目介绍 定位&#xff1a;专门为餐饮企业&#xff08;餐厅、饭店&#xff09;定制的一款软件产品 功能架构&#xff1a; 管理端 - 外卖商家使用 用户端 - 点餐用户使用 技术栈&#xff1a; 开发环境的搭建 整体结构&#xff1a; 前端环境 前端工程基于 nginx 运行 - Ngi…

能源物联网数据采集设备 串口服务器功能参数介绍

摘要 ​随着物联网技术的快速发展&#xff0c;各种传统设备的联网需求愈发迫切。串口服务器作为一种桥接传统串口设备与现代网络的关键设备&#xff0c;在工业控制、智能电网、交通运输等域发挥了重要作用。本文以APort100串口服务器为例&#xff0c;探讨串口服务器在现代物联…

20250118拿掉荣品pro-rk3566开发板上Android13下在uboot和kernel启动阶段的Rockchip这个LOGO标识

20250118拿掉荣品pro-rk3566开发板上Android13下在uboot和kernel启动阶段的Rockchip这个LOGO标识 2025/1/18 15:12 缘起&#xff1a;做飞凌OK3588-C开发板/核心板【Linux R4】的时候&#xff0c;测试/生产要求没有开机LOGO【飞凌/Rockchip】 要求&#xff1a;黑屏或者中性界面。…

【STM32-学习笔记-4-】PWM、输入捕获(PWMI)

文章目录 1、PWMPWM配置 2、输入捕获配置3、编码器 1、PWM PWM配置 配置时基单元配置输出比较单元配置输出PWM波的端口 #include "stm32f10x.h" // Device headervoid PWM_Init(void) { //**配置输出PWM波的端口**********************************…

RocketMQ源码之消息刷盘分析

前言 刷盘是将内存中的消息写入磁盘,分为同步刷盘和异步刷盘。同步刷盘指一条消息写入磁盘才返回成功,异步刷盘指写入内存就返回成功,稍后异步线程刷盘。 在创建CommitLog对象的时候,会初始化刷盘服务: //代码位置:org.apache.rocketmq.store.CommitLog public CommitL…

navicat 折线图或面积图

折线图或面积图将信息显示为以直线段连接的一系列数据点。 折线图 面积图 堆积面积图 图表属性 选择图表类型后&#xff0c;可以更改其属性来自定义图表&#xff1a; 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 不透明度 设置背景颜色的不透明度。 显示边框…

【数模学习笔记】插值算法和拟合算法

声明&#xff1a;以下笔记中的图片以及内容 均整理自“数学建模学习交流”清风老师的课程资料&#xff0c;仅用作学习交流使用 文章目录 插值算法定义三个类型插值举例插值多项式分段插值三角插值 一般插值多项式原理拉格朗日插值法龙格现象分段线性插值 牛顿插值法 Hermite埃尔…

机器学习皮马印第安人糖尿病数据集预测报告

目录 1.项目选题与设计方案 1.1项目选题 1.2设计方案 2.功能实现 2.1 主要功能介绍 2.2 开发环境及平台介绍 2.3 实现过程 2.3.1数据分析 2.3.2算法设计 2.3.3 python代码 3.个人心得体会 1.项目选题与设计方案 1.1项目选题 我国的糖尿病患者初诊时约&#xff18;&a…