webFlux入门

article/2025/8/29 2:16:44

今天发现一个特别好的文章,是关于springBoot框架中响应式编程的,那下面就是这位博主所整理的一些干货👇

------------------------------------------------------------

1. WebFlux介绍

Spring WebFlux 是 Spring Framework 5.0中引入的新的响应式web框架。与Spring MVC不同,它不需要Servlet API,是完全异步且非阻塞的,并且通过Reactor项目实现了Reactive Streams规范。

Spring WebFlux 用于创建基于事件循环执行模型的完全异步且非阻塞的应用程序。

(PS:所谓异步非阻塞是针对服务端而言的,是说服务端可以充分利用CPU资源去做更多事情,这与客户端无关,客户端该怎么请求还是怎么请求。)

Reactive Streams是一套用于构建高吞吐量、低延迟应用的规范。而Reactor项目是基于这套规范的实现,它是一个完全非阻塞的基础,且支持背压。Spring WebFlux基于Reactor实现了完全异步非阻塞的一套web框架,是一套响应式堆栈。

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

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

2. Spring WebFlux Framework

Spring WebFlux有两种风格:功能性和基于注释的。基于注释的与Spring MVC非常相近。例如:

 1 @RestController2 @RequestMapping("/users")3 public class MyRestController {4 5     @GetMapping("/{user}")6     public Mono<User> getUser(@PathVariable Long user) {7     // ...8     }9 
10     @GetMapping("/{user}/customers")
11     public Flux<Customer> getUserCustomers(@PathVariable Long user) {
12     // ...
13     }
14     
15     @DeleteMapping("/{user}")
16     public Mono<User> deleteUser(@PathVariable Long user) {
17     // ...
18     }
19 } 

与之等价,也可以这样写:

 1 @Configuration2 public class RoutingConfiguration {3     @Bean4     public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {5         return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)6             .andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)7             .andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);8     }9 }
10 
11 @Component
12 public class UserHandler {
13     public Mono<ServerResponse> getUser(ServerRequest request) {
14     // ...
15     }
16     public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
17     // ...
18     }
19     public Mono<ServerResponse> deleteUser(ServerRequest request) {
20     // ...
21     }
22 }

如果你同时添加了spring-boot-starter-web和spring-boot-starter-webflux依赖,那么Spring Boot会自动配置Spring MVC,而不是WebFlux。你当然可以强制指定应用类型,通过SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE) 

3. Hello WebFlux

pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">4     <modelVersion>4.0.0</modelVersion>5     <parent>6         <groupId>org.springframework.boot</groupId>7         <artifactId>spring-boot-starter-parent</artifactId>8         <version>2.2.5.RELEASE</version>9         <relativePath/> <!-- lookup parent from repository -->
10     </parent>
11     <groupId>com.cjs.example</groupId>
12     <artifactId>cjs-reactive-rest-service</artifactId>
13     <version>0.0.1-SNAPSHOT</version>
14     <name>cjs-reactive-rest-service</name>
15 
16     <properties>
17         <java.version>1.8</java.version>
18     </properties>
19 
20     <dependencies>
21         <dependency>
22             <groupId>org.springframework.boot</groupId>
23             <artifactId>spring-boot-starter-webflux</artifactId>
24         </dependency>
25 
26         <dependency>
27             <groupId>org.springframework.boot</groupId>
28             <artifactId>spring-boot-starter-test</artifactId>
29             <scope>test</scope>
30             <exclusions>
31                 <exclusion>
32                     <groupId>org.junit.vintage</groupId>
33                     <artifactId>junit-vintage-engine</artifactId>
34                 </exclusion>
35             </exclusions>
36         </dependency>
37         <dependency>
38             <groupId>io.projectreactor</groupId>
39             <artifactId>reactor-test</artifactId>
40             <scope>test</scope>
41         </dependency>
42     </dependencies>
43 
44     <build>
45         <plugins>
46             <plugin>
47                 <groupId>org.springframework.boot</groupId>
48                 <artifactId>spring-boot-maven-plugin</artifactId>
49             </plugin>
50         </plugins>
51     </build>
52 
53 </project>

GreetingHandler.java 

 1 package com.cjs.example.restservice.hello;2 3 import org.springframework.http.MediaType;4 import org.springframework.stereotype.Component;5 import org.springframework.web.reactive.function.BodyInserters;6 import org.springframework.web.reactive.function.server.ServerRequest;7 import org.springframework.web.reactive.function.server.ServerResponse;8 import reactor.core.publisher.Mono;9 
10 import java.util.concurrent.atomic.AtomicLong;
11 
12 /**
13  * @author ChengJianSheng
14  * @date 2020-03-25
15  */
16 @Component
17 public class GreetingHandler {
18 
19     private final AtomicLong counter = new AtomicLong();
20 
21     /**
22      * A handler to handle the request and create a response
23      */
24     public Mono<ServerResponse> hello(ServerRequest request) {
25         return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
26                 .body(BodyInserters.fromValue("Hello, Spring!"));
27 
28     }
29 }

GreetingRouter.java

 1 package com.cjs.example.restservice.hello;2 3 import org.springframework.context.annotation.Bean;4 import org.springframework.context.annotation.Configuration;5 import org.springframework.http.MediaType;6 import org.springframework.web.reactive.function.server.*;7 8 /**9  * @author ChengJianSheng
10  * @date 2020-03-25
11  */
12 @Configuration
13 public class GreetingRouter {
14 
15     /**
16      * The router listens for traffic on the /hello path and returns the value provided by our reactive handler class.
17      */
18     @Bean
19     public RouterFunction<ServerResponse> route(GreetingHandler greetingHandler) {
20         return RouterFunctions.route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), greetingHandler::hello);
21     }
22 }

GreetingWebClient.java

 1 package com.cjs.example.restservice.hello;2 3 import org.springframework.http.MediaType;4 import org.springframework.web.reactive.function.client.ClientResponse;5 import org.springframework.web.reactive.function.client.WebClient;6 import reactor.core.publisher.Mono;7 8 /**9  * @author ChengJianSheng
10  * @date 2020-03-25
11  */
12 public class GreetingWebClient {
13 
14     /**
15      * For reactive applications, Spring offers the WebClient class, which is non-blocking.
16      *
17      * WebClient can be used to communicate with non-reactive, blocking services, too.
18      */
19     private WebClient client = WebClient.create("http://localhost:8080");
20 
21     private Mono<ClientResponse> result = client.get()
22             .uri("/hello")
23             .accept(MediaType.TEXT_PLAIN)
24             .exchange();
25 
26     public String getResult() {
27         return ">> result = " + result.flatMap(res -> res.bodyToMono(String.class)).block();
28     }
29 }

Application.java

 1 package com.cjs.example.restservice;2 3 import com.cjs.example.restservice.hello.GreetingWebClient;4 import org.springframework.boot.SpringApplication;5 import org.springframework.boot.autoconfigure.SpringBootApplication;6 7 /**8  * @author ChengJianSheng9  * @date 2020-03-25
10  */
11 @SpringBootApplication
12 public class CjsReactiveRestServiceApplication {
13 
14     public static void main(String[] args) {
15         SpringApplication.run(CjsReactiveRestServiceApplication.class, args);
16 
17         GreetingWebClient gwc = new GreetingWebClient();
18         System.out.println(gwc.getResult());
19     }
20 
21 } 

可以直接在浏览器中访问 http://localhost:8080/hello  

GreetingRouterTest.java

 1 package com.cjs.example.restservice;2 3 import org.junit.jupiter.api.Test;4 import org.junit.jupiter.api.extension.ExtendWith;5 import org.springframework.beans.factory.annotation.Autowired;6 import org.springframework.boot.test.context.SpringBootTest;7 import org.springframework.http.MediaType;8 import org.springframework.test.context.junit.jupiter.SpringExtension;9 import org.springframework.test.web.reactive.server.WebTestClient;
10 
11 @ExtendWith(SpringExtension.class)
12 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
13 public class GreetingRouterTest {
14 
15     @Autowired
16     private WebTestClient webTestClient;
17 
18     /**
19      * Create a GET request to test an endpoint
20      */
21     @Test
22     public void testHello() {
23         webTestClient.get()
24                 .uri("/hello")
25                 .accept(MediaType.TEXT_PLAIN)
26                 .exchange()
27                 .expectStatus().isOk()
28                 .expectBody(String.class).isEqualTo("Hello, Spring!");
29     }
30 
31 }

4. Reactor 核心特性

Mono: implements Publisher and returns 0 or 1 elements

Flux: implements Publisher and returns N elements

5. Spring Data Redis

pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">4     <modelVersion>4.0.0</modelVersion>5     <parent>6         <groupId>org.springframework.boot</groupId>7         <artifactId>spring-boot-starter-parent</artifactId>8         <version>2.2.6.RELEASE</version>9         <relativePath/> <!-- lookup parent from repository -->
10     </parent>
11     <groupId>com.cjs.example</groupId>
12     <artifactId>cjs-webflux-hello</artifactId>
13     <version>0.0.1-SNAPSHOT</version>
14     <name>cjs-webflux-hello</name>
15 
16     <properties>
17         <java.version>1.8</java.version>
18     </properties>
19 
20     <dependencies>
21         <dependency>
22             <groupId>org.springframework.boot</groupId>
23             <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
24         </dependency>
25         <dependency>
26             <groupId>org.springframework.boot</groupId>
27             <artifactId>spring-boot-starter-webflux</artifactId>
28         </dependency>
29 
30         <dependency>
31             <groupId>org.apache.commons</groupId>
32             <artifactId>commons-pool2</artifactId>
33             <version>2.8.0</version>
34         </dependency>
35         <dependency>
36             <groupId>com.alibaba</groupId>
37             <artifactId>fastjson</artifactId>
38             <version>1.2.67</version>
39         </dependency>
40         <dependency>
41             <groupId>org.projectlombok</groupId>
42             <artifactId>lombok</artifactId>
43             <optional>true</optional>
44         </dependency>
45         <dependency>
46             <groupId>org.springframework.boot</groupId>
47             <artifactId>spring-boot-starter-test</artifactId>
48             <scope>test</scope>
49             <exclusions>
50                 <exclusion>
51                     <groupId>org.junit.vintage</groupId>
52                     <artifactId>junit-vintage-engine</artifactId>
53                 </exclusion>
54             </exclusions>
55         </dependency>
56         <dependency>
57             <groupId>io.projectreactor</groupId>
58             <artifactId>reactor-test</artifactId>
59             <scope>test</scope>
60         </dependency>
61     </dependencies>
62 
63     <build>
64         <plugins>
65             <plugin>
66                 <groupId>org.springframework.boot</groupId>
67                 <artifactId>spring-boot-maven-plugin</artifactId>
68             </plugin>
69         </plugins>
70     </build>
71 
72 </project>

UserController.java

 1 package com.cjs.example.webflux.controller;2 3 import com.alibaba.fastjson.JSON;4 import com.cjs.example.webflux.domain.User;5 import org.springframework.beans.factory.annotation.Autowired;6 import org.springframework.data.redis.core.ReactiveHashOperations;7 import org.springframework.data.redis.core.ReactiveStringRedisTemplate;8 import org.springframework.web.bind.annotation.*;9 import reactor.core.publisher.Mono;
10 
11 /**
12  * @author ChengJianSheng
13  * @date 2020-03-27
14  */
15 @RestController
16 @RequestMapping("/users")
17 public class UserController {
18 
19 
20     @Autowired
21     private ReactiveStringRedisTemplate reactiveStringRedisTemplate;
22 
23     @GetMapping("/hello")
24     public Mono<String> hello() {
25         return Mono.just("Hello, Reactive");
26     }
27 
28     @PostMapping("/save")
29     public Mono<Boolean> saveUser(@RequestBody User user) {
30         ReactiveHashOperations hashOperations = reactiveStringRedisTemplate.opsForHash();
31         return hashOperations.put("USER_HS", String.valueOf(user.getId()), JSON.toJSONString(user));
32     }
33 
34     @GetMapping("/info/{id}")
35     public Mono<User> info(@PathVariable Integer id) {
36         ReactiveHashOperations reactiveHashOperations = reactiveStringRedisTemplate.opsForHash();
37         Mono<String> hval = reactiveHashOperations.get("USER_HS", String.valueOf(id));
38         return hval.map(e->JSON.parseObject(e, User.class));
39     }
40 
41 }

CoffeeController.java

 1 package com.cjs.example.webflux.controller;2 3 import com.cjs.example.webflux.domain.Coffee;4 import org.springframework.data.redis.core.*;5 import org.springframework.web.bind.annotation.GetMapping;6 import org.springframework.web.bind.annotation.PathVariable;7 import org.springframework.web.bind.annotation.RequestMapping;8 import org.springframework.web.bind.annotation.RestController;9 import reactor.core.publisher.Flux;
10 import reactor.core.publisher.Mono;
11 
12 /**
13  * Spring WebFlux is the new reactive web framework introduced in Spring Framework 5.0.
14  * Unlike Spring MVC, it does not require the Servlet API, is fully asynchronous and non-blocking,
15  * and implements the Reactive Streams specification through the Reactor project.
16  *
17  * @author ChengJianSheng
18  * @date 2020-03-27
19  */
20 @RestController
21 @RequestMapping("/coffees")
22 public class CoffeeController {
23 
24     private final ReactiveRedisOperations<String, Coffee> coffeeOps;
25 
26     public CoffeeController(ReactiveRedisOperations<String, Coffee> coffeeOps) {
27         this.coffeeOps = coffeeOps;
28     }
29 
30     @GetMapping("/getAll")
31     public Flux<Coffee> getAll() {
32         return coffeeOps.keys("*").flatMap(coffeeOps.opsForValue()::get);
33     }
34 
35     @GetMapping("/info/{id}")
36     public Mono<Coffee> info(@PathVariable String id) {
37         ReactiveValueOperations valueOperations = coffeeOps.opsForValue();
38         return valueOperations.get(id);
39     }
40 } 

最后,也是非常重要的一点:异步非阻塞并不会使程序运行得更快。WebFlux 并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性。

Spring WebFlux 是一个异步非阻塞的 Web 框架,所以,它特别适合应用在 IO 密集型的服务中,比如微服务网关这样的应用中。

Reactive and non-blocking generally do not make applications run faster.

6. Docs

Spring | Home

Spring | Reactive

Reactor 3 Reference Guide

Reactor 3 Reference Guide

Index of /spring-framework/docs

Spring Framework Documentation

Web on Reactive Stack

Web on Reactive Stack

转载自:https://www.cnblogs.com/cjsblog/p/12580518.html

原作者:废物大师兄


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

相关文章

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常见数据…

redis的五种数据类型

🏆作者简介:哪吒,CSDN2022博客之星Top1、CSDN2021博客之星Top2、多届新星计划导师✌、博客专家💪 ,专注Java硬核干货分享,立志做到Java赛道全网Top N。 🏆本文收录于,Java基础教程系列,目前已经700+订阅,CSDN最强Java专栏,包含全部Java基础知识点、Java8新特性、…

Redis 的五种基本数据类型

一、String 类型 1.1 介绍 String 类型&#xff0c;也就是字符串类型&#xff0c;是 Redis 中最简单的存储类型。其 value 是字符串&#xff0c;不过根据字符串的格式不同&#xff0c;又可以分为 3 类&#xff1a; string&#xff1a;普通字符串int&#xff1a;整数类型&…

【Redis学习】Redis10大数据类型

总体概述 这里说的数据类型是value的数据类型&#xff0c;key的类型都是字符串。 redis字符串&#xff08;String&#xff09; string是redis最基本的类型&#xff0c;一个key对应一个Tvalue。 string类型是二进制安全的&#xff0c;意思是redis的string可以包含任何数据&am…