WebFlux 简介

article/2025/8/29 2:14:43

目录

一、关于WebFlux

二、SpringMVC与SpringWebFlux

三、Reactive Spring Web

  HttpHandler

  WebHandler

四、实现WebFlux 实例

基于Annotated Controller方式实现

WebFluxConfig配置:

Controller:

Main方法:

函数式编程方式

集成Thymeleaf

springWebFlux 是 SpringFrameworl5.0 添加的新功能,WebFlux 本身是追随当下最火的Reactive Programming 而诞生的框架,那么本编就来简述下这个框架到底是做什么的。

一、关于WebFlux

我们知道传统的Web框架,比如说:struts2,springmvc等都是基于Servlet API与Servlet容器基础之上运行的,在Servlet3.1之后才有了异步非阻塞的支持。而WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现的。相对于传统的web框架来说,它可以运行在诸如Netty,Undertow及支持Servlet3.1的容器上,因此它的运行环境的可选择行要比传统web框架多的多。

  根据官方的说法,webflux主要在如下两方面体现出独有的优势:

  1)非阻塞式

    其实在servlet3.1提供了非阻塞的API,WebFlux提供了一种比其更完美的解决方案。使用非阻塞的方式可以利用较小的线程或硬件资源来处理并发进而提高其可伸缩性

  2) 函数式编程端点

    老生常谈的编程方式了,Spring5必须让你使用java8,那么函数式编程就是java8重要的特点之一,而WebFlux支持函数式编程来定义路由端点处理请求。

二、SpringMVC与SpringWebFlux

我们先来看官网的一张图:

  它们都可以用注解式编程模型,都可以运行在tomcat,jetty,undertow等servlet容器当中。但是SpringMVC采用命令式编程方式,代码一句一句的执行,这样更有利于理解与调试,而WebFlux则是基于异步响应式编程,对于初次接触的码农们来说会不习惯。对于这两种框架官方给出的建议是:

  1)如果原先使用用SpringMVC好好的话,则没必要迁移。因为命令式编程是编写、理解和调试代码的最简单方法。因为老项目的类库与代码都是基于阻塞式的。

  2)如果你的团队打算使用非阻塞式web框架,WebFlux确实是一个可考虑的技术路线,而且它支持类似于SpringMvc的Annotation的方式实现编程模式,也可以在微服务架构中让WebMvc与WebFlux共用Controller,切换使用的成本相当小

  3)在SpringMVC项目里如果需要调用远程服务的话,你不妨考虑一下使用WebClient,而且方法的返回值可以考虑使用Reactive Type类型的,当每个调用的延迟时间越长,或者调用之间的相互依赖程度越高,其好处就越大。

  我个人意见是:官网明确指出,SpringWebFlux并不是让你的程序运行的更快(相对于SpringMVC来说),而是在有限的资源下提高系统的伸缩性,因此当你对响应式编程非常熟练的情况下并将其应用于新的系统中,还是值得考虑的,否则还是老老实实的使用WebMVC吧

三、Reactive Spring Web

在这里定义了最基本的服务端接口:HttpHandler和WebHandler

  HttpHandler

  HttpHandler 定义了最基本的处理Http请求行为,这个接口主要作用是处理Http请求并将结果做出响应,下面这个表格是说明了Server API的使用方式及何种方式进行响应式流支持的:

Server nameServer API usedReactive Streams support

Netty

Netty API

Reactor Netty

Undertow

Undertow API

spring-web: Undertow to Reactive Streams bridge

Tomcat

Servlet 3.1 non-blocking I/O; Tomcat API to read and write ByteBuffers vs byte[]

spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge

Jetty

Servlet 3.1 non-blocking I/O; Jetty API to write ByteBuffers vs byte[]

spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge

Servlet 3.1 container

Servlet 3.1 non-blocking I/O

spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge

  WebHandler

  WebHandler 定义了Web 请求必要的一些处理行为,大家不妨想想看:WebFlux已经脱离了Servlet API,那么使用WebFlux时遇到会话机制怎么办,想要对请求过滤处理怎么办或者想要处理静态资源怎么办等等,那么WebHandler 就是做这个事情的。其实在HttpHandler的基本实现类通过适配器模式及装饰模式也间接的实现了WebHandler接口:

   WebHandler常见的实现类,我在这里列举一下:

  •    WebHandlerDecorator:WebHandler的装饰器,利用装饰模式实现相关功能的扩展
  •    HttpWebHandlerAdapter: 进行Http请求处理,同时也是HttpHandler的实现类
  •    FilteringWebHandler:通过WebFilter进行过滤处理的类,类似于Servlet中的Filter
  •    ExceptionHandlingWebHandler: 针对于异常的处理类
  •    ResourceWebHandler:用于静态资源请求的处理类
  •    DispatcherHandler:请求的总控制器,类似于WebMVC中的DispatcherServlet

四、实现WebFlux 实例

建立SpringBoot项目,注意SpringBoot版本必须为2.0.0+,在build.gradle配置文件里写:

 compile('org.springframework.boot:spring-boot-starter-webflux')

基于Annotated Controller方式实现

WebFluxConfig配置:

package com.hzgj.framework.study.springwebflux.web.reactive;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.DispatcherHandler;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;@Configuration
@ComponentScan
@EnableWebFlux
public class WebFluxConfig implements WebFluxConfigurer {@Beanpublic WebHandler webHandler(ApplicationContext applicationContext) {DispatcherHandler dispatcherHandler = new DispatcherHandler(applicationContext);return dispatcherHandler;}
}

在这里我们创建一个WebHandler 并使用@EnableWebFlux 打开相关功能。我们可以发现与SpringMVC 的WebConfig 配置真的好像

Controller:

package com.hzgj.framework.study.springwebflux.web.reactive.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class IndexController {@GetMapping("/index")public String index() {return "index";}
}

  在这里与SpringMVC定义的Controller无异

Main方法:

package com.hzgj.framework.study.springwebflux.web.reactive;import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import reactor.ipc.netty.http.server.HttpServer;import java.io.IOException;/*** 基于Reactor Netty实现WebFlux服务
* @author chen.nie
* @date 2018/7/13
**/
public class SpringWebfluxApplication {public static void main(String[] args) throws IOException {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(WebFluxConfig.class);//通过ApplicationContext创建HttpHandlerHttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(applicationContext).build();ReactorHttpHandlerAdapter httpHandlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);HttpServer.create("localhost",8080).newHandler(httpHandlerAdapter).block();System.in.read();}
}

  程序启动成功后即可通过http://localhost:8080/index拿到对应结果

函数式编程方式

  使用这种方式请先了解Java8提供的函数式编程特性。那么我们先编写一个简单的Handler

package com.hzgj.framework.study.springwebflux.web.reactive.handler;import org.springframework.beans.BeanUtils;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;import static org.springframework.http.MediaType.*;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;/*** 类似于Controller,处理用户请求的真实逻辑*/
public class StudentHandler {public static Mono<ServerResponse> selectStudent(ServerRequest request) {Student studentBody = new Student();request.bodyToMono(Student.class).subscribe(student -> BeanUtils.copyProperties(student, studentBody));return ok().contentType(APPLICATION_JSON_UTF8).body(fromObject(studentBody));}public static Mono<ServerResponse> insertStudent(ServerRequest request){return ok().contentType(TEXT_PLAIN).body(fromObject("success"));}private static class Student {private Integer id;private String name;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
}

  这个Handler类似于Controller的作用,在这里的返回值均为Mono类型,其中ServerRequest 和 ServerResponse,大家可以先理解为WebFlux替代ServletRequest 与ServletResponse 对象的,而且这些类能够支持异步。

  Main方法里我们创建的HttpHandler的方式需要进行改变一下,同样用函数式方式进行编写:

package com.hzgj.framework.study.springwebflux.web.reactive;import com.hzgj.framework.study.springwebflux.web.reactive.handler.StudentHandler;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import reactor.ipc.netty.http.server.HttpServer;import java.io.IOException;import static org.springframework.web.reactive.function.server.RequestPredicates.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;public class FunctionRouteApplication {public static void main(String[] args) throws IOException {HttpHandler httpHandler = toHttpHandler(route(POST("/selectStudent").and(accept(MediaType.APPLICATION_JSON_UTF8)), StudentHandler::selectStudent).and(route(GET("/saveStudent"), StudentHandler::insertStudent)));ReactorHttpHandlerAdapter httpHandlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);HttpServer.create("localhost", 8080).newHandler(httpHandlerAdapter).block();System.in.read();}
}

启动成功后,我们用postman测试一下

此时我们可以看到使用函数式编程创建路由端点,也可以实现同样的功能。

集成Thymeleaf

@Configuration
@EnableWebFlux
@ComponentScan
public class WebFluxConfig implements WebFluxConfigurer, ApplicationContextAware {private ApplicationContext applicationContext;@Beanpublic SpringResourceTemplateResolver templateResolver() {SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();templateResolver.setApplicationContext(applicationContext);templateResolver.setPrefix("classpath:/templates/");templateResolver.setSuffix(".html");templateResolver.setCharacterEncoding("UTF-8");return templateResolver;}@Beanpublic SpringWebFluxTemplateEngine templateEngine() {SpringWebFluxTemplateEngine templateEngine = new SpringWebFluxTemplateEngine();templateEngine.setTemplateResolver(templateResolver());return templateEngine;}@Beanpublic ThymeleafReactiveViewResolver viewResolver() {ThymeleafReactiveViewResolver viewResolver = new ThymeleafReactiveViewResolver();viewResolver.setTemplateEngine(templateEngine());return viewResolver;}@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {registry.viewResolver(viewResolver());}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

在这里注意一下,在webflux中不支持直接创建Bean的方式配置视图解析器,我们可以参考下面的源码:WebFluxConfiguraitonSupport

@Beanpublic ViewResolutionResultHandler viewResolutionResultHandler() {ViewResolverRegistry registry = getViewResolverRegistry();List<ViewResolver> resolvers = registry.getViewResolvers();ViewResolutionResultHandler handler = new ViewResolutionResultHandler(resolvers, webFluxContentTypeResolver(), webFluxAdapterRegistry());handler.setDefaultViews(registry.getDefaultViews());handler.setOrder(registry.getOrder());return handler;}

我们在这里可以明确看到这个是通过ViewResolverRegistry来取的,因此我们只能通过 configureViewResolvers(ViewResolverRegistry registry) 来进行配置

 

转自:

https://www.cnblogs.com/niechen/p/9303451.html

特别推荐:

Spring 5 新增全新的reactive web框架:webflux


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

相关文章

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…

【Redis7学习日记】—— Redis十大数据类型

一、十大类型概述 首先&#xff0c;我们要知道此处的数据类型指的是 value 的类型&#xff0c;Redis 的 key 都是字符串类型我们通过一张图&#xff0c;先大致了解一下这些数据结构的样子 1.1 String 类型 String 是 Redis 中最基本的数据类型&#xff0c;一个 key 对应一个…