Spring:Webflux响应式编程

article/2025/8/29 2:07:36

目录

  • 简介
  • 响应式编程
    • Reactor
      • 信号
      • 操作符
    • SpringWebflux 执行流程和API
  • 注解实现SpringWebflux

说明:基于atguigu学习笔记。

简介

Webflux是 Spring5 添加新的模块,用于 web 开发的,功能和 SpringMVC 类似的,Webflux 使用当前一种比较流程响应式编程出现的框架。

使用传统 web 框架,比如 SpringMVC,这些基于 Servlet 容器,Webflux 是一种异步非阻塞的框架,异步非阻塞的框架在 Servlet3.1 以后才支持,核心是基于Reactor 的相关 API 实现的。

Webflux 特点:

  • 非阻塞式:在有限资源下,提高系统吞吐量和伸缩性,以 Reactor 为基础实现响应式编程
  • 函数式编程:Spring5 框架基于 java8,Webflux 使用 Java8 函数式编程方式实现路由请求

比较 SpringMVC:
在这里插入图片描述
第一:两个框架都可以使用注解方式,都运行在 Tomet 等容器中
第二:SpringMVC 采用命令式编程,Webflux 采用异步响应式编程

响应式编程

响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。

Reactor

Reactor 框架是 Pivotal 基于 Reactive Programming 思想实现的。

Reactor 有两个核心类,Mono 和 Flux,这两个类实现接口 Publisher,提供丰富操作符。Flux 对象实现发布者,返回 N 个元素;Mono 实现发布者,返回 0 或者 1 个元素。

信号

Flux 和 Mono 都是数据流的发布者,使用 Flux 和 Mono 都可以发出三种数据信号:元素值,错误信号,完成信号,错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者。

示例:
1.引入依赖

<dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> <version>3.1.5.RELEASE</version>
</dependency>

2.代码

package com.example.springdemo3;import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;public class Test01 {public static void main(String[] args) {//just 方法直接声明Flux.just(1,2,3,4);Mono.just(1);//其他的方法Integer[] array = {1,2,3,4};Flux.fromArray(array);List<Integer> list = Arrays.asList(array);Flux.fromIterable(list);Stream<Integer> stream = list.stream();Flux.fromStream(stream);}
}

三种信号特点

  • 错误信号和完成信号都是终止信号,不能共存的
  • 如果没有发送任何元素值,而是直接发送错误或者完成信号,表示是空数据流
  • 如果没有错误信号,没有完成信号,表示是无限数据流

调用 just 或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅什么都不会发生。示例如下:

package com.example.springdemo3;import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;public class Test01 {public static void main(String[] args) {//just 方法直接声明Flux.just(1,2,3,4).subscribe(System.out::println);Mono.just(1).subscribe(System.out::println);;}
}

操作符

操作符对数据流进行一道道操作,成为操作符,比如工厂流水线。有以下两个操作符:

1.map

将一个数据流里的每个元素映射为新元素,返回一个新的流。
在这里插入图片描述

2.flatMap
把每个元素转换成数据流,把转换之后多个流合并一个大的数据流
在这里插入图片描述

SpringWebflux 执行流程和API

SpringWebflux 基于 Reactor,默认使用容器是 Netty,Netty 是高性能的 NIO 框架,异步非阻
塞的框架。

SpringWebflux 执行过程和 SpringMVC 相似的,SpringWebflux 核心控制器 DispatchHandler,实现了接口 WebHandler。WebHandler的源码如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.web.server;import reactor.core.publisher.Mono;public interface WebHandler {Mono<Void> handle(ServerWebExchange var1);
}

可以看到只有一个方法WebHandler,WebHandler的实现在DispatcherHandler类中,实现逻辑如下:

public Mono<Void> handle(ServerWebExchange exchange) {return this.handlerMappings == null ? this.createNotFoundError() : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {return mapping.getHandler(exchange);}).next().switchIfEmpty(this.createNotFoundError()).flatMap((handler) -> {return this.invokeHandler(exchange, handler);}).flatMap((result) -> {return this.handleResult(exchange, result);});}

其中,参数ServerWebExchange是放http请求和响应信息;getHandler根据请求地址获取对应的mapping;invokeHandler调用具体的业务方法;handleResult处理结果返回。

SpringWebflux 里面 的DispatcherHandler,有3个很重要的属性,如下:

public class DispatcherHandler implements WebHandler, ApplicationContextAware {@Nullableprivate List<HandlerMapping> handlerMappings;@Nullableprivate List<HandlerAdapter> handlerAdapters;@Nullableprivate List<HandlerResultHandler> resultHandlers;
}

HandlerMapping:请求查询到处理的方法; HandlerAdapter:真正负责请求处理;HandlerResultHandler:响应结果处理。

SpringWebflux 实现函数式编程,两个接口:RouterFunction(路由处理)
和 HandlerFunction(处理函数)。

注解实现SpringWebflux

使用注解编程模型方式,和 SpringMVC 使用相似的,只需要把相关依赖配置到项目中,
SpringBoot 自动配置相关运行容器,默认情况下使用 Netty 服务器。

1.创建项目
创建springboot项目,引入依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>spring-demo3</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-demo3</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.3.7.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-test</artifactId><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version><configuration><mainClass>com.example.springdemo3.SpringDemo3Application</mainClass></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

2.创建包和相关类

实体类:

package com.example.springdemo3.entity;import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class User {private String name;private String gender;private Integer age;}

service接口:

package com.example.springdemo3.service;import com.example.springdemo3.entity.User;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;public interface UserService {//根据 id 查询用户Mono<User> getUserById(int id);//查询所有用户Flux<User> getAllUser();//添加用户Mono<Void> saveUserInfo(Mono<User> user);
}

service实现类

package com.example.springdemo3.service.impl;import com.example.springdemo3.entity.User;
import com.example.springdemo3.service.UserService;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.util.HashMap;
import java.util.Map;@Service
public class UserServiceImpl implements UserService {//创建 map 集合存储数据private final Map<Integer,User> users = new HashMap<>();public UserServiceImpl() {this.users.put(1,new User("lucy","nan",20));this.users.put(2,new User("mary","nv",30));this.users.put(3,new User("jack","nv",50));}@Overridepublic Mono<User> getUserById(int id) {return Mono.justOrEmpty(this.users.get(id));}@Overridepublic Flux<User> getAllUser() {return Flux.fromIterable(this.users.values());}@Overridepublic Mono<Void> saveUserInfo(Mono<User> userMono) {return userMono.doOnNext(person -> {//向 map 集合里面放值int id = users.size()+1;users.put(id,person);}).thenEmpty(Mono.empty()); // Mono.empty()是终止信号}
}

注意这里没有真正和数据库交互,而是维护了一个数组,模拟数据库。

controller类:

package com.example.springdemo3.controller;import com.example.springdemo3.entity.User;
import com.example.springdemo3.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;@Component
@RestController
public class UserController {//注入 service@Autowiredprivate UserService userService;//id 查询@GetMapping("/user/{id}")public Mono<User> geetUserId(@PathVariable int id) {return userService.getUserById(id);}//查询所有@GetMapping("/user")public Flux<User> getUsers() {return userService.getAllUser();}//添加@PostMapping("/saveuser")public Mono<Void> saveUser(@RequestBody User user) {Mono<User> userMono = Mono.just(user);return userService.saveUserInfo(userMono);}
}

SpringMVC 方式实现,同步阻塞的方式,基于 SpringMVC+Servlet+Tomcat
SpringWebflux 方式实现,异步非阻塞 方式,基于 SpringWebflux+Reactor+Netty


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

相关文章

WebFlux入门详解

文章目录 一、 WebFlux介绍1、什么是 WebFlux2、反应式库介绍2.1 Reactive Stream2.2 Reactor2.3 Reactive Stream、Reactor 和 WebFlux 关系 二、入门WebFlux1、简单介绍2、简单的例子构造 三、WebFlux与数据库1、介绍2、r2dbc实战前期准备2.1 引入依赖与配置2.2 创建数据表2.…

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五种数据结构…