Spring-webflux 响应式编程

article/2025/8/29 2:03:23

热爱可抵漫长岁月

文章目录

    • 1. 前言
    • 2. Spring-webflux简介
    • 3. 什么是“响应式”
    • 4. Spring-webflux的响应式API
    • 5. Spring MVC 还是 WebFlux?
    • 6. 并发模型
    • 7. webflux使用
    • 8. 测试

1. 前言

Spring 提供了两个并行堆栈。一种是基于带有 Spring MVC 和 Spring Data 结构的 Servlet API。另一个是完全反应式堆栈,它利用了 Spring WebFlux 和 Spring Data 的反应式存储库。在这两种情况下,Spring Security 都提供了对两种堆栈的支持。

在这里插入图片描述

反应式宣言

在这里插入图片描述

2. Spring-webflux简介

Spring WebFlux 是在 5.0 版中添加的。它是完全无阻塞的,支持 Reactive Streams背压,并且可以在 Netty、Undertow 和 Servlet 3.1+ 容器等服务器上运行。

Spring-webflux官网

3. 什么是“响应式”

所谓响应式,举个例子,当调用一个api获取数据时,无需阻塞等待数据返回,而是当有数据返回时会进行告知。可见响应式是非阻塞的,意味着调用方法后,CPU可以去做别的事情,当接收到数据响应时CPU再回来处理,这种方式提高了系统的吞吐量。

而响应式编程,其实是为这种异步非阻塞的流式编程制定的一套标准。流式编程已不陌生了,Java8提供的stream api就是这种风格。这套标准包括对运行环境(JVM、JavaScript)以及网络协议相关的规范。

和传统的阻塞式servlet容器不一样。响应式容器能进一步提高资源的利用率,避免线程长时间处于等待状态,能以较少的线程处理更多的请求,缺点是整个处理链路必须是异步的,是基于事件响应的,不能阻塞事件线程,不然服务器性能会急剧下降,当然spring webflux并不能完整的替代传统的阻塞式容器,可根据需求进行选型。

应用案例Geteway

在这里插入图片描述

所有微服务的请求都会通过网关,如果采用mvc 对于并发量有一定的瓶颈。

4. Spring-webflux的响应式API

Spring-webflux框架是基于Reactor这个开源项目开发的。Reactor框架是跟Spring紧密配合的。

里边提供了两种API类型,分别是MonoFlux

  • Mono表示0 或 1个元素,
  • Flux表示0 至 N个元素,

5. Spring MVC 还是 WebFlux?

这两个web框架分别代表着两种不同类型的编程流派,官方给出了一个图作为对比如下

在这里插入图片描述

建议考虑以下具体点:

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

  • Spring WebFlux 提供与该领域中其他人相同的执行模型优势,并且还提供服务器选择(Netty、Tomcat、Jetty、Undertow 和 Servlet 3.1+ 容器)、编程模型(带注释的控制器和功能性 Web 端点)的选择,以及反应库(Reactor、RxJava 或其他)的选择。

  • 如果您对用于 Java 8 lambda 或 Kotlin 的轻量级、功能性 Web 框架感兴趣,您可以使用 Spring WebFlux 功能性 Web 端点。对于要求不那么复杂的小型应用程序或微服务来说,这也是一个不错的选择,它们可以从更高的透明度和控制中受益。

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

  • 评估应用程序的一种简单方法是检查其依赖关系。如果您要使用阻塞持久性 API(JPA、JDBC)或网络 API,那么 Spring MVC 至少是常见架构的最佳选择。Reactor 和 RxJava 在单独的线程上执行阻塞调用在技术上是可行的,但您不会充分利用非阻塞 Web 堆栈。

  • 如果您有一个调用远程服务的 Spring MVC 应用程序,请尝试响应式WebClient. 您可以直接从 Spring MVC 控制器方法返回反应类型(Reactor、RxJava或其他)。每个呼叫的延迟或呼叫之间的相互依赖性越大,好处就越显着。Spring MVC 控制器也可以调用其他响应式组件。

  • 如果您有一个大型团队,请记住向非阻塞、函数式和声明式编程转变的陡峭学习曲线。在没有完全开关的情况下启动的一种实用方法是使用 reactive WebClient。除此之外,从小处着手并衡量收益。我们预计,对于广泛的应用,这种转变是不必要的。如果您不确定要寻找什么好处,请先了解非阻塞 I/O 的工作原理(例如,单线程 Node.js 上的并发性)及其影响。

其次: webflux兼容大部分springmvc的注解,也可以像mvc那样创建controller处理请求。

区别:

  • WebFlux是完全异步非阻塞的,SpringMVC是同步阻塞的。
  • WebFlux采用异步响应式编程,SpringMVC采用命令式编程。
  • WebFlux由于完全异步,所有操作数据库的框架,以及数据库也都要求是支持异步的,所以目前不支持Mybatis、不支持Oracle数据库。

6. 并发模型

尽管webmvcwebflux都支持使用注解来定义一个Controller,但是其实现方式完全不同。

webmvc是一个Servlet应用,实现是阻塞式IO,其维护一个线程池来处理每一个用户请求,也就是当Servlet容器启动时,就会创建比如10个线程出来,因此系统吞吐量的瓶颈在于有限的连接数和阻塞的请求处理过程。

webflux可以基于netty这样的NIO网络框架,它只需要很少的几个工作线程(Event loop worker)就能够处理并响应请求。由于无需阻塞等待方法返回,CPU资源就得到了更好的利用。

webflux并不能让程序运行地更快;而是提高了并发处理请求的能力,即提高系统吞吐量

7. webflux使用

pom依赖:

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

定义对象:

public class Person {private Integer id;private Integer age;private String name;public Person(Integer id, Integer age, String name) {this.id = id;this.age = age;this.name = name;}public Person() {}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Person{" +"id=" + id +", age=" + age +", name='" + name + '\'' +'}';}
}

然后定义PersonController,响应式风格中不再使用@RequestMapping声明地址映射,而是通过RouterFunctions.route().GET()方法:

@Configuration
public class PersonRouter {@Resourceprivate PersonHandler personHandler;@Beanpublic RouterFunction<ServerResponse> personRoutes() {return RouterFunctions.route().GET("/person/{id}", RequestPredicates.accept(MediaType.APPLICATION_JSON), personHandler::getPerson).GET("/person", RequestPredicates.accept(MediaType.APPLICATION_JSON), personHandler::listPeople).POST("/person", personHandler::createPerson).build();}
}

PersonHandler中处理对应的HTTP请求,等同于MVC架构中的Service层

@Component
public class PersonHandler {@Resourceprivate IPersonDao personDao;public Mono<ServerResponse> listPeople(ServerRequest request) {Flux<Person> people = personDao.getList();return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(people, Person.class);}public Mono<ServerResponse> createPerson(ServerRequest request) {return request.bodyToMono(Person.class).flatMap(i -> personDao.savePerson(i)).flatMap(p -> ServerResponse.ok().bodyValue(p));}public Mono<ServerResponse> getPerson(ServerRequest request) {int personId = Integer.parseInt(request.pathVariable("id"));return personDao.getPerson(personId).flatMap(person -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).bodyValue(person)).switchIfEmpty(ServerResponse.notFound().build());}
}

IPersonDao

public interface IPersonDao {/*** 获取所有person* @author: yh* @date: 2022/9/4* @return Flux<Person>*/Flux<Person> getList();/*** 保存对象* @param person person* @author: yh* @date: 2022/9/4* @return Mono<Void>*/Mono<Void> savePerson(Person person);/*** 根据id查询* @param id id* @author: yh* @date: 2022/9/4* @return Mono<Person>*/Mono<Person> getPerson(Integer id);
}

PersonDao

@Component
public class PersonDao implements IPersonDao {private final List<Person> personList = new ArrayList<>();public PersonDao() {this.personList.add(new Person(1, 17, "张三"));this.personList.add(new Person(2, 18, "李四"));}@Overridepublic Flux<Person> getList() {return Flux.fromIterable(personList);}@Overridepublic Mono<Void> savePerson(Person person) {personList.add(person);System.out.println("personList.size = " + personList);return Mono.empty();}@Overridepublic Mono<Person> getPerson(Integer id) {return Mono.justOrEmpty(personList.stream().filter(p -> p.getId().equals(id)).findFirst());}
}
@SpringBootApplication
@EnableWebFlux
public class SpringWebfluxSessionApplication implements WebFluxConfigurer {public static void main(String[] args) {SpringApplication.run(SpringWebfluxSessionApplication.class, args);}
}

8. 测试

通过启动日志可以证实Spring-webflux是默认使用Netty提供HTTP服务

在这里插入图片描述

GET请求:http://127.0.0.1:8080/person
在这里插入图片描述

POST请求:http://127.0.0.1:8080/person

boyd:

{"id": 9,"age": 17,"name": "张三"
}

在这里插入图片描述

控制台输出:
在这里插入图片描述

GET请求:http://127.0.0.1:8080/person/9
在这里插入图片描述


完整代码已上传 Gitee Spring整合常用组件

到此,本章内容就介绍完啦,如果有帮助到你 欢迎点个赞👍👍👍吧!!您的鼓励是博主的最大动力! 有问题评论区交流。


http://chatgpt.dhexx.cn/article/8bIvjJb7.shtml

相关文章

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…

redis数据类型(5种)和底层实现

redis数据类型(5种)和底层实现 Redis的特点 要用好Redis&#xff0c;首先要明白它的特点&#xff1a; 读写速度快。redis官网测试读写能到10万左右每秒。速度快的原因这里简单说一下&#xff0c;第一是因为数据存储在内存中&#xff0c;我们知道机器访问内存的速度是远远大于…

Redis数据类型及编码

Redis数据类型及编码 说到Redis的数据类型&#xff0c;我们大概会很快想到Redis的5种常见的数据类型&#xff1a;字符串(String)、列表(List)、散列(Hash)、集合(Set)、有序集合(Sorted Set)&#xff0c;以及他们的特点和运用场景及常用命令。不过在讲五大数据类型之前&#x…

Redis 基础 -- Redis数据类型之set

文章目录 1. Redis数据类型之set1.1 set类型介绍1.2 set类型基本操作1.3 set 类型数据的扩展操作&#xff1a;获取随机的数据1.4 set 类型数据的扩展操作&#xff1a;集合的交、并、差集1.4.1 sinter命令1.4.2 sunion命令1.4.3 sdiff命令1.4.4 sinterstore命令1.4.5 sunionstor…

Redis 数据类型

1、string类型 &#xff08;1&#xff09;存储的数据&#xff1a;单个数据&#xff0c;最简单的数据存储类型&#xff0c;也是最常用的数据存储类型。 string&#xff0c;他就是存一个字符串儿&#xff0c;注意是value那一部分是一个字符串&#xff0c;它是redis中最基本、最…

NoSQL数据库之Redis(三):常用五大数据类型

目录 Redis键(key)常用命令 Redis字符串(String)常用命令原子性数据结构 Redis列表(List)常用命令数据结构 Redis集合(Set)常用命令数据结构 Redis哈希(Hash)常用命令数据结构 Redis有序集合Zset(sorted set)常用命令数据结构跳跃表&#xff08;跳表&#xff09; redis常见数据…