目录

  • 简介
  • 响应式编程
    • 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

Spring:Webflux响应式编程相关推荐

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

    第一章 Reactive Stream 第1节 jdk9的响应式流 就是reactive stream,也就是flow.其实和jdk8的stream没有一点关系.说白了就一个发布-订阅模式,一共只有4 ...

  2. Spring WebFlux 响应式编程学习笔记(一)

    各位Javaer们,大家都在用SpringMVC吧?当我们不亦乐乎的用着SpringMVC框架的时候,Spring5.x又悄(da)无(zhang)声(qi)息(gu)的推出了Spring WebFl ...

  3. Spring web-flux 响应式编程

    1.基于传统的结构 Demo (仅仅作为快速了解,生产环境不会用这种) 请求处理类 Controller 类 package com.yootk.webflux.handler; import org ...

  4. Spring WebFlux – SpringReact式编程

    Spring WebFlux is the new module introduced in Spring 5. Spring WebFlux is the first step towards re ...

  5. WebFlux响应式编程

    文章目录 概要 入门WebFlux WebClient 概要 在SpringMvc框架下,http的请求是同步的,在某些场景下为了提供性能,可以采用异步的方式来进行优化.WebFlux便是提供了异步的 ...

  6. WebFlux响应式编程基础之 4 reactive stream 响应式流

    reactive stream 响应式流 - 简而言之,就是多了一个沟通的渠道 发布订阅者 背压 交流 Reactive Stream主要接口 java.util.concurrent.Flow 源码 ...

  7. WebFlux响应式编程基础之 2 函数式编程 工具jclasslib bytecode viewer

    函数式编程:告诉他的功能是什么,而不是告诉他怎么做 命令式编程:怎么去做 函数式编程:不需要关注细节,利用系统已经有的API 使用jdk8自带函数接口的好处 函数接口减少接口定义 函数式接口链式操作 ...

  8. WebFlux响应式编程基础之 5 webflux服务端开发讲解

    https://blog.csdn.net/qq_27093465/article/details/64124330 debug技巧 第5章 webflux服务端开发讲解 Spring5 非组塞的开发 ...

  9. flux服务器推消息,在Spring WebFlux响应式处理程序中发送JMS消息:它是否阻塞?

    这是反应性处理的正确方法吗?我看到2个线程一个反应性的nio,直到并包括flatMap(fareRepo :: save).另一个线程是计算线程,它从发送消息开始,一直持续到ServerRespons ...

最新文章

  1. 编程语言与思维:科技公司如何自我重构?
  2. 【完结】总结12大CNN主流模型架构设计思想
  3. Go出现警告struct doesn‘t have any exported fields, nor custom marshaling
  4. Qt实现对json文件的解析
  5. java pdf水印排布问题_java 实现 PDF 加水印功能
  6. 怎样管理Lotus Domino
  7. java 传参数 数组_Java参数传递 数组的使用
  8. 导 Kinect2库,opencv库,pcl库
  9. Python写excel练习
  10. android 4.2 dropbox,android 下用脚本备份文档到dropbox的实现
  11. 经济学计算机会成本和贸易区直的题,管理经济学2017年4月真题(02628)
  12. 2020 第一周工作总结:TAGE分支预测器算法
  13. 使用Galen进行Responsive Web测试四部曲
  14. 配置chrony服务,实现服务器时间自动同步
  15. mac恢复文件的方法,在Mac上使用时间机器恢复文件
  16. 判断英伟达显卡计算力及是否支持FP16和INT8
  17. android 机器人动画,画一个可以动的Android 小机器人
  18. 连续函数的运算与初等函数的连续性——“高等数学”
  19. Word插入希腊字母及特殊符号 分类整
  20. NO29、最小的K个数(应该记住大顶堆和小顶堆的区别与联系,并不难)

热门文章

  1. apollo配置中心之--spring boot如何加载apollo
  2. win11新机开荒-常规软件安装
  3. 使用github-profile-readme-generator美化你的README
  4. 奥比中光(Deeyea)配置树莓派
  5. 奥比中光进军世界的历程
  6. db2嵌套查询效率_提高DB2 查询性能的常用方法
  7. 关于Max导出插件的七七八八
  8. Getting Started with ARI(ARI入门)
  9. 约瑟夫环问题(递推公式)
  10. html 的函数写法,react中函数的不同写法的区别是什么?