WebFlux入门详解

article/2025/8/29 2:18:41

文章目录

  • 一、 WebFlux介绍
    • 1、什么是 WebFlux
    • 2、反应式库介绍
      • 2.1 Reactive Stream
      • 2.2 Reactor
      • 2.3 Reactive Stream、Reactor 和 WebFlux 关系
  • 二、入门WebFlux
    • 1、简单介绍
    • 2、简单的例子构造
  • 三、WebFlux与数据库
    • 1、介绍
    • 2、r2dbc实战前期准备
      • 2.1 引入依赖与配置
      • 2.2 创建数据表
      • 2.3 创建相关类
    • 3、WebFlux接口的两种方式
      • 3.1 基于注解的方式
      • 3.2 基于Functional Endpoints方式
  • 四、总结

一、 WebFlux介绍

1、什么是 WebFlux

WebFlux官网

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

Spring WebFlux 是一个异步非阻塞式 IO 模型,通过少量的容器线程就可以支撑大量的并发访问。底层使用的是 Netty 容器,这点也和传统的 SpringMVC 不一样,SpringMVC 是基于 Servlet 的。但是接口的响应时间并不会因为使用了 WebFlux 而缩短,服务端的处理结果还是得由 worker 线程处理完成之后再返回给前端。

  • 【spring-webmvc + Servlet + Tomcat】命令式的、同步阻塞的

  • 【spring-webflux + Reactor + Netty】响应式的、异步非阻塞的

同时要学习 WebFlux 时我发现又需要 Java 8 中的函数式编程、Stream 流等技术作为前置知识,对于lambda和stream流,可以参考:https://blog.csdn.net/lemon_TT/article/details/119415154

2、反应式库介绍

2.1 Reactive Stream

反应式编程(Reactive Programming) ,这是微软为了应对高并发环境下的服务端编程,提出的一个实现异步编程的方案。

反应式流(Reactive Stream) 就是反应式编程相关的规范,在 Java 平台上,由Netflix(开发了 RxJava)、TypeSafe(开发了 Scala、Akka)、Pivatol(开发了 Spring、Reactor)共同制定。

它由以下几个组件组成:

  • 发布者:发布元素到订阅者

  • 订阅者:消费元素

  • 订阅:在发布者中,订阅被创建时,将与订阅者共享

  • 处理器:发布者与订阅者之间处理数据

比如Java 平台直到 JDK 9才提供了对于Reactive的完整支持,JDK9也定义了上述提到的四个接口,在java.util.concurrent包上

// 发布者(生产者)
public interface Publisher<T> {public void subscribe(Subscriber<? super T> s);
}
// 订阅者(消费者)
public interface Subscriber<T> {public void onSubscribe(Subscription s);public void onNext(T t);public void onError(Throwable t);public void onComplete();
}
// 用于发布者与订阅者之间的通信(实现背压:订阅者能够告诉生产者需要多少数据)
public interface Subscription {public void request(long n);public void cancel();
}
// 用于处理发布者 发布消息后,对消息进行处理,再交由消费者消费
public interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
}

2.2 Reactor

Reactive Stream 是一套反应式编程的规范,但作为应用程序 API,应用程序肯定还是需要一个更高级、更丰富的功能 API 来编写异步逻辑。这就是反应式库所扮演的角色。

Reactor 框架是 Pivotal 基于 Reactive Programming 思想实现的。它符合 Reactive Streams 规范。它提供了MonoFlux API 类型,通过一组与 ReactiveX 运算符词汇表一致的丰富运算符来处理 0…1 () 和 0…N ()的数据序列。是一个用于 JVM 的完全非阻塞的响应式编程框架,具备高效的需求管理,可以很好的处理 “backpressure”。**Reactor **就是 Spring WebFlux 的首选 反应式库。

Flux 和 Mono 这两个 Reactor 的核心类,两个都是发布者 Publisher。

  • Mono:实现发布者 Publisher,并返回 0 或 1 个元素。

  • Flux:实现发布者 Publisher,并返回 N 个元素。

2.3 Reactive Stream、Reactor 和 WebFlux 关系

  • Reactive Stream 是一套反应式编程标准和规范

  • Reactor 是基于 Reactive Streams 一套反应式编程框架

  • WebFlux 以 Reactor 为基础,实现 Web 领域的 反应式编程框架。

在这里插入图片描述

二、入门WebFlux

1、简单介绍

经过上面的基础,我们现在已经能够得出一些结论的了:

  • WebFlux是Spring推出响应式编程的一部分(web端)

  • 响应式编程是异步非阻塞的(是一种基于数据流(data stream)和变化传递(propagation of change)的声明式(declarative)的编程范式)

Spring官方为了让我们更加快速/平滑到WebFlux上,之前SpringMVC那套都是支持的。也就是说:我们可以像使用SpringMVC一样使用着WebFlux。WebFlux使用的响应式流并不是用JDK9平台的,而是一个叫做Reactor响应式流库。Reactor是一个响应式流,它也有对应的发布者(Publisher ),Reactor的发布者用两个类来表示:

  • Mono(返回0或1个元素)

  • Flux(返回0 - n个元素)

而消费者则是Spring框架帮我们去完成

2、简单的例子构造

首先创建项目,在pom.xml引入相关依赖,也可以在常见时勾选Spring Reactive Web

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

新建文件

@RestController
public class HelloController {private static final Logger log = LoggerFactory.getLogger(HelloController.class);//普通方法@GetMapping("/hello")public String hello() {log.info("开始时间:" + System.currentTimeMillis());String result = createStr();log.info("结束时间:" + System.currentTimeMillis());return result;}// Mono方法@GetMapping("/mono")public Mono<String> mono() {log.info("开始时间:" + System.currentTimeMillis());Mono<String> result = Mono.fromSupplier(this::createStr);log.info("结束时间:" + System.currentTimeMillis());return result;}// 服务器推送(SSE - >Server Send Event)@GetMapping(value = "/flux",produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> flux() {Flux<String> result = Flux.fromStream(IntStream.range(1,5).mapToObj(i->{try {TimeUnit.SECONDS.sleep(1);}catch (InterruptedException ignored){}return "flux data--"+ i;}));return result;}// 阻塞5秒钟private String createStr() {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}return "hello world";}
}

对于前两个方法来说,从调用者(浏览器)的角度而言,是感知不到有什么变化的,因为都是得等待5s才返回数据。但是,从服务端的日志我们可以看出,WebFlux是直接返回Mono对象的(而不是像SpringMVC一直同步阻塞5s,线程才返回)。这正是WebFlux的好处:能够以固定的线程来处理高并发(充分发挥机器的性能)。

第三个方法是WebFlux支持服务器推送(SSE - >Server Send Event),即从服务器推送到客户端。

三、WebFlux与数据库

1、介绍

Spring Boot 2.3.0.RELEASE 开始才正式支持基于 R2DBC 的 MySQL 驱动。

R2DBC: R2DBC 是 Spring 官方在 Spring5 发布了响应式 Web 框架 Spring WebFlux 之后急需能够满足异步响应的数据库交互 API,不过由于缺乏标准和驱动,Pivotal 团队开始自己研究响应式关系型数据库连接 Reactive Relational Database Connectivity,并提出了 R2DBC 规范 API 用来评估可行性并讨论数据库厂商是否有兴趣支持响应式的异步非阻塞驱动程序。最早只有 PostgreSQL 、H2、MSSQL 三家数据库厂商,现在 MySQL也加入进来了。

2、r2dbc实战前期准备

2.1 引入依赖与配置

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency><groupId>dev.miku</groupId><artifactId>r2dbc-mysql</artifactId><scope>runtime</scope>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>

yml配置连接

server:port: 8080
spring:r2dbc:username: rootpassword: rooturl: r2dbcs:mysql://localhost:3306/webflux?characterEncoding=utf-8&serverTimezone=GMT%2B8

2.2 创建数据表

CREATE TABLE `test_user`  (`user_id` int NOT NULL AUTO_INCREMENT,`user_name` varchar(255),`age` int,`address` varchar(255) ,PRIMARY KEY (`user_id`) USING BTREE
) 

2.3 创建相关类

实体类

@Table("test_user")
public class User {@Idprivate int userId;private String userName;private int age;private String address;// 省略 getter、setter
}

UserRepository,就相当于 DAO

public interface UserRepository extends ReactiveCrudRepository<User, Integer> {
}

3、WebFlux接口的两种方式

3.1 基于注解的方式

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserRepository userRepository;@RequestMapping("/getAllUser")public Flux<User> getAllUser() {Flux<User> userFlux = userRepository.findAll();return userFlux;}@RequestMapping("/addUser")public Mono<User> addUser(User user) {Mono<User> mono = userRepository.save(user);return mono;}
}

3.2 基于Functional Endpoints方式

  • 这个配置类的作用有点像 SpringMVC 中的 DispatcherServlet,负责请求的分发,根据不同的请求 URL,找到对应的处理器去处理。

  • 通过 RouterFunctions 这样一个工具类来创建 RouterFunction 实例。

  • 首先调用 nest 方法,第一个参数配置的相当于是接下来配置的地址的一个前缀,这有点类似于我们在 Controller 类上直接写 @RequestMapping 注解去配置地址。

  • nest 方法的第二个参数就是 RouterFunction 实例了,每一个 RouterFunction 实例通过 RouterFunctions.route 方法来构建,它的第一个参数就是请求的 URL 地址(注意这个时候配置的地址都是有一个共同的前缀),第二个参数我们通过方法引用的方式配置了一个 HandlerFunction,这个就是当前请求的处理器了。

  • 通过 addRoute 方法可以配置多个路由策略。

创建 Userhandler.java

package com.example.webflux.controller;import com.example.webflux.dao.UserRepository;
import com.example.webflux.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.ServerResponse.notFound;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;/*** @author shawn* @version 1.0* @date 2022/4/22 16:04*/
@Component
public class Userhandler {@AutowiredUserRepository userRepository;public Mono<ServerResponse> getAllUsers(ServerRequest serverRequest) {return ok().contentType(APPLICATION_JSON).body(userRepository.findAll(), User.class);}public Mono<ServerResponse> addUser(ServerRequest serverRequest) {return ok().contentType(APPLICATION_JSON).body(userRepository.saveAll(serverRequest.bodyToMono(User.class)), User.class);}public Mono<ServerResponse> deleteUser(ServerRequest serverRequest) {return userRepository.findById(Integer.valueOf(serverRequest.pathVariable("userId"))).flatMap(user -> userRepository.delete(user).then(ok().build())).switchIfEmpty(notFound().build());}
}

创建 RouterConfiguration

@Configuration
public class RouterConfiguration {@BeanRouterFunction<ServerResponse> userRouterFunction(UserHandler userHandler) {return RouterFunctions.nest(RequestPredicates.path("/user"),RouterFunctions.route(RequestPredicates.GET("/getAllUser"), userHandler::getAllUsers).andRoute(RequestPredicates.POST("/addUser"), userHandler::addUser).andRoute(RequestPredicates.DELETE("/{userId}"), userHandler::deleteUser));}
}

四、总结

  • 如果原先使用用SpringMVC好好的话,则没必要迁移。因为命令式编程是编写、理解和调试代码的最简单方法。因为老项目的类库与代码都是基于阻塞式的。

  • 如果你的团队打算使用非阻塞式web框架,WebFlux确实是一个可考虑的技术路线,而且它支持类似于SpringMvc的Annotation的方式实现编程模式,也可以在微服务架构中让WebMvc与WebFlux共用Controller,切换使用的成本相当小。

  • 在SpringMVC项目里如果需要调用远程服务的话,你不妨考虑一下使用WebClient,而且方法的返回值可以考虑使用Reactive Type类型的,当每个调用的延迟时间越长,或者调用之间的相互依赖程度越高,其好处就越大。

  • 在微服务架构中,您可以混合使用Spring MVC或Spring WebFlux控制器或Spring WebFlux功能端点的应用程序。在两个框架中支持相同的基于注释的编程模型,可以更轻松地重用知识,同时为正确的工作选择正确的工具。

Spring WebFlux 并不是让你的程序运行的更快(相对于SpringMVC来说),而是在有限的资源下提高系统的伸缩性,因此当你对响应式编程非常熟练的情况下并将其应用于新的系统中,还是值得考虑的,否则还是老老实实的使用WebMVC。


参考文献

外行人都能看懂的WebFlux

WebFlux 详解


http://chatgpt.dhexx.cn/article/nL34Cr2U.shtml

相关文章

springboot之webmvc和webflux浅析

webmvc和webflux作为spring framework的两个重要模块&#xff0c;代表了两个IO模型&#xff0c;阻塞式和非阻塞式。 1、webmvc webmvc是基于servlet的阻塞式模型&#xff0c;一个请求到达服务器后会单独分配一个线程去处理请求&#xff0c;如果请求包含IO操作&#xff0c;线程…

Webflux核心

什么是WebFlux? Spring WebFlux 是一套全新的 Reactive Web 栈技术&#xff0c;实现完全非阻塞&#xff0c;支持 Reactive Streams 背压等特性&#xff0c;并且运行环境不限于 Servlet 容器&#xff08;Tomcat、Jetty、Undertow&#xff09;&#xff0c;如 Netty 等。Spring W…

SpringBoot Webflux解析

1. Webflux介绍 Webflux是一种异步非阻塞的IO模型&#xff0c;当有请求过来时&#xff0c;它会将请求交由worker线程去处理&#xff0c;这样就可以极大的提升吞吐量&#xff0c;所以他比较适合用于IO密集型的场景。 webflux虽然可以给我带来吞吐量的提升&#xff0c;但是同时也…

Webflux快速入门

传统的Web框架&#xff0c;如struts2&#xff0c;springmvc等都是基于Servlet API与Servlet容器基础之上运行的&#xff0c;在Servlet3.1之后才有了异步非阻塞的支持。而WebFlux是一个典型非阻塞异步的框架&#xff0c;它的核心是基于Reactor的相关API实现的。相对于传统的web框…

Spring-webflux 响应式编程

热爱可抵漫长岁月 文章目录 1. 前言2. Spring-webflux简介3. 什么是“响应式”4. Spring-webflux的响应式API5. Spring MVC 还是 WebFlux&#xff1f;6. 并发模型7. webflux使用8. 测试 1. 前言 Spring 提供了两个并行堆栈。一种是基于带有 Spring MVC 和 Spring Data 结构的 …

Spring Webflux - 01 MVC的困境

文章目录 Spring MVC的困境Servlet 异步请求缓解线程池压力Servlet 3.0 异步请求处理Code 演示工程pom配置文件启动类同步servlet演示 异步servlet辅助Code演示 Tomcat 请求处理流程以及异步请求工作原理 Spring MVC的困境 我们先看一段工作中大家常见的代码 RestController …

WebFlux的使用

什么是WebFlux springWebFlux 是 SpringFrameworlk5.0 添加的新功能&#xff0c;它是完全非阻塞的&#xff0c;支持Reactive Stream及背压&#xff0c;可以运行于Netty、Undertow等服务器&#xff0c;及Servlet 3.1容器。 webflux主要在如下两方面体现出独有的优势&#xff1a;…

webFlux入门

今天发现一个特别好的文章&#xff0c;是关于springBoot框架中响应式编程的&#xff0c;那下面就是这位博主所整理的一些干货&#x1f447; ------------------------------------------------------------ 1. WebFlux介绍 Spring WebFlux 是 Spring Framework 5.0中引入的新…

WebFlux 简介

目录 一、关于WebFlux 二、SpringMVC与SpringWebFlux 三、Reactive Spring Web HttpHandler WebHandler 四、实现WebFlux 实例 基于Annotated Controller方式实现 WebFluxConfig配置&#xff1a; Controller: Main方法&#xff1a; 函数式编程方式 集成Thymeleaf sp…

Spring Webflux 响应式编程 (二) - WebFlux编程实战

第一章 Reactive Stream 第1节 jdk9的响应式流 就是reactive stream&#xff0c;也就是flow。其实和jdk8的stream没有一点关系。说白了就一个发布-订阅模式&#xff0c;一共只有4个接口&#xff0c;3个对象&#xff0c;非常简单清晰。 什么是背压&#xff1f; 背压是指订阅者…

WebFlux 详解

今天我们开始来学习下 WebFlux&#xff0c;为什么突然要学这个东西&#xff1f; 因为我之前是想学习 Spring Cloud Gateway 来着&#xff0c;然后发现它是基于 Spring5.0SpringBoot2.0WebFlux等技术开发的。所以学之前才要来简单了解下 WebFlux 技术。 然后要学习 WebFlux 时…

Redis常用数据类型及其对应的底层数据结构

Redis数据库 Redis是一种键值(Key-Value)数据库。相较于MySQL之类的关系型数据库&#xff0c;Redis是一种非关系型数据库。Redis存储的数据只包含键和值两部分&#xff0c;只能通过键来查询值。这样简单的存储结构&#xff0c;能让Redis的读写效率非常高(HashMap读写效率都是O…

二. Redis 数据类型

2.1 Redis 字符串 (String) 2.1.1 概述 String 是 Redis 最基本的类型&#xff0c;你可以理解成与 Memcached 一模一样的类型&#xff0c;一个 key 对应一个 value。 String 类型是二进制安全的。意味着 Redis 的 string 可以包含任何数据。比如 jpg 图片或者序列化的对象。 …

Redis数据类型Hash

文章目录 Hash类型介绍hash 类型数据的基本操作 hash 类型数据操作的注意事项Hash和String类型的区别 有时候我们往往不是在缓存中存一个值&#xff0c;而是选择存一个对象&#xff0c;比如一个购物车消息&#xff0c;我们就需要使用到hash了 Hash类型介绍 新的存储需求&…

Redis数据类型String

文章目录 数据存储类型介绍String类型String类型的基本操作String单数据操作和多数据操作的选择问题string 类型数据的扩展操作数据增加指定范围的值String 设置数据指定的生命周期string 类型数据操作的注意事项 数据存储类型介绍 常用的五个数据类型: string --------------…

Redis数据类型 - 散列(Map)

文章目录 一、散列简介二、散列的基本操作三、散列与字符串比较1、散列键的优点2、字符串键的优点 一、散列简介 散列就是hash或者说Map&#xff0c;Redis的散列键会将一个键和一个散列在数据库中关联起来&#xff0c;可以在散列中设置任意多个字符串键值对&#xff0c;因此通…

redis数据类型插入输出命令

进入客户机&#xff1a;redis-cli 中文字符不能显示&#xff1a;redis-cli --raw、get Course:1:Cname 一、redis数据类型数据的添加 1、String 添加数据&#xff1a;set StringTest(数据名称) “helloword”(数据) 显示数据&#xff1a;get StringTest&#xff08;数据名称&am…

Redis数据类型及使用场景

转自&#xff1a; http://www.kubiji.cn/juhe-id7106.html Redis数据类型及使用场景 来源&#xff1a; WQTech阅读&#xff1a; 2936 时间&#xff1a;2 小时前 摘要&#xff1a;Redis相比其它的KV数据库,其一大特点是支持丰富的数据类型.它一共支持5种数据类型,下面逐一介绍这…

Redis数据类型与操作命令

1. 键值对数据库 1.1 redis数据结构 redis的数据是 key-value 形式的键值对&#xff0c;其中 key 其实都是字符串的形式&#xff0c;而 value 的数据类型&#xff0c;也就是数据的保存形式&#xff0c;底层实现的方式就用到了数据结构。 所以我们一直说的“redis五种数据结构…

Redis数据类型

文章目录 STRINGLISTSETHASHZSET Redis主要有5种数据类型&#xff0c;包括String&#xff0c;List&#xff0c;Set&#xff0c;Zset&#xff0c;Hash&#xff0c;满足大部分的使用要求&#xff0c;Redis各数据类型的使用场景可以参考Redis使用场景 数据类型可以存储的值操作ST…