Spring零基础入门WebFlux响应式编程

作者:一根头发学一年 时间:2022-07-12 07:25:53 

说明:基于atguigu学习笔记。

简介

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

使用传统 web 框架,比如 SpringMVC,这些基于 Servlet 容器,Webflux 是一种异步非阻

塞的框架,异步非阻塞的框架在 Servlet3.1 以后才支持,核心是基于 Reactor 的相关 API 实现

的。

Webflux 特点:

  • 非阻塞式:在有限资源下,提高系统吞吐量和伸缩性,以 Reactor 为基础实现响应式编程

  • 函数式编程:Spring5 框架基于 java8,Webflux 使用 Java8 函数式编程方式实现路由请求

比较 SpringMVC:

Spring零基础入门WebFlux响应式编程

第一:两个框架都可以使用注解方式,都运行在 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

将一个数据流里的每个元素映射为新元素,返回一个新的流。

Spring零基础入门WebFlux响应式编程

2.flatMap

把每个元素转换成数据流,把转换之后多个流合并一个大的数据流

Spring零基础入门WebFlux响应式编程

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 {
   @Nullable
   private List<HandlerMapping> handlerMappings;
   @Nullable
   private List<HandlerAdapter> handlerAdapters;
   @Nullable
   private 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));
   }
   @Override
   public Mono<User> getUserById(int id) {
       return Mono.justOrEmpty(this.users.get(id));
   }
   @Override
   public Flux<User> getAllUser() {
       return Flux.fromIterable(this.users.values());
   }
   @Override
   public 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
   @Autowired
   private 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

来源:https://blog.csdn.net/qq_43745578/article/details/127169208

标签:Spring,WebFlux,响应式编程
0
投稿

猜你喜欢

  • Android Studio导入jar包过程详解

    2023-01-02 08:04:51
  • spring boot mybatis枚举映射示例代码

    2023-03-01 11:45:51
  • C# httpwebrequest访问HTTPS错误处理方法

    2021-10-31 02:40:49
  • Android图片色彩变换实现方法

    2022-03-21 07:23:32
  • .net的命名空间类库的简单介绍

    2023-01-19 17:56:27
  • C#条件语句、循环语句(if、while)

    2023-09-27 19:49:23
  • SpringBoot+easypoi实现数据的Excel导出

    2023-04-05 12:27:19
  • AlertDialog点击按钮不消失的实现方法

    2023-12-12 07:11:16
  • Android自定义ScrollView实现放大回弹效果实例代码

    2022-10-15 11:00:58
  • Java图片裁剪和生成缩略图的实例方法

    2023-11-09 00:01:50
  • Java过滤器模式原理及用法实例

    2023-03-07 12:15:07
  • C#调用易语言写的Dll文件方法

    2023-07-21 01:56:10
  • java实现滑动验证解锁

    2023-06-02 12:16:36
  • Android Studio 3.0 新功能全面解析和旧项目适配问题

    2022-09-16 23:53:57
  • Android开发仿映客送礼物效果

    2023-03-24 01:11:12
  • 使用Maven配置Spring的方法步骤

    2023-02-05 18:37:46
  • C#中if语句使用概述

    2022-08-31 23:22:09
  • Android互联网访问图片并在客户端显示的方法

    2021-12-26 21:25:10
  • JAVA的LIST接口的REMOVE重载方法调用原理解析

    2021-07-20 16:35:27
  • Java Pattern和Matcher字符匹配方式

    2022-06-07 21:57:56
  • asp之家 软件编程 m.aspxhome.com