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

各位Javaer们,大家都在用SpringMVC吧?当我们不亦乐乎的用着SpringMVC框架的时候,Spring5.x又悄(da)无(zhang)声(qi)息(gu)的推出了Spring WebFlux。web? 不是已经有SpringMVC这么好用的东西了么,为啥又冒出个WebFlux? 这玩意儿是什么鬼?

Spring WebFlux特性

异步非阻塞

SpringMVC是同步阻塞的IO模型,资源浪费相对来说比较严重,当我们在处理一个比较耗时的任务时,例如:上传一个比较大的文件,首先,服务器的线程一直在等待接收文件,在这期间它就像个傻子一样等在那儿(放学别走),什么都干不了,好不容易等到文件来了并且接收完毕,我们又要将文件写入磁盘,在这写入的过程中,这根线程又再次懵bi了,又要等到文件写完才能去干其它的事情。这一前一后的等待,不浪费资源么?

没错,Spring WebFlux就是来解决这问题的,Spring WebFlux可以做到异步非阻塞。还是上面那上传文件的例子,Spring WebFlux是这样做的:线程发现文件还没准备好,就先去做其它事情,当文件准备好之后,通知这根线程来处理,当接收完毕写入磁盘的时候(根据具体情况选择是否做异步非阻塞),写入完毕后通知这根线程再来处理(异步非阻塞情况下)。这个用脚趾头都能看出相对SpringMVC而言,可以节省系统资源。666啊,有木有!

响应式(reactive)函数编程

如果你觉得java8的lambda写起来很爽,那么,你会再次喜欢上Spring WebFlux,因为它支持函数式编程,得益于对于reactive-stream的支持(通过reactor框架来实现的),喜欢java8 stream的又有福了。为什么要函数式编程? 这个别问我,我也不知道,或许是因为bi格高吧,哈哈,开玩笑啦。

不再拘束于Servlet容器

以前,我们的应用都运行于Servlet容器之中,例如我们大家最为熟悉的Tomcat, Jetty...等等。而现在Spring WebFlux不仅能运行于传统的Servlet容器中(前提是容器要支持Servlet3.1,因为非阻塞IO是使用了Servlet3.1的特性),还能运行在支持NIO的Netty和Undertow中。

所以,看完Spring WebFlux的新特性之后,内心五味杂陈的我,只能用一个表情来形容:

bq__%E4%BB%80%E4%B9%88%E7%8E%A9%E6%84%8F.jpg

但是学习还是要学的,毕竟Spring推出的......

Spring WebFlux是随Spring 5推出的响应式Web框架。建立在异步非阻塞的IO框架之上的一个新的,其基本的架构如下:
getImage?fileId=5a929813ab644121e3000f8c

Spring提供了完整的支持响应式的服务端技术栈。

如上图所示,左侧为基于spring-webmvc的技术栈,右侧为基于spring-webflux的技术栈,可以看到SpringMVC技术栈给予Serverlet容器,如Tomcat容器,SpringWebFlux基于HTTP/Reactive Stream.

WebFlux 依赖构建

依赖于SpringBoot的强大,我们只要在配置文件添加依赖即可。

Gradle 依赖

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

或者Maven构建的依赖于

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

SpringMVC注解方式实现

Spring团队在开发WebFlux上尽量和SpringMVC靠拢,因此我们可以直接使用一个简单的SpringMVC项目有改造成Spring WebFlux的项目,具体如下。

改造 Spring MVC

下面是我们再熟悉不过的接口应用,访问http://localhost:8080/mono 即可看到返回了一个字符串

   @GetMapping("/mono")public String baseApi() {return "Hello,Reactive Program";}

改造后的内容如下:

    @GetMapping("/mono")public Mono<String> baseApi() {                  //1return Mono.just("Hello,Reactive Program");   //2}

主要有两处改造

  • 1 返回的不再是简单的对象,而是使用的是Mono封装的单个文档信息(返回集合使用Flux)

  • 2 返回的时候我们需要构造一个Mono类型的数据,因此使用Mono.just(T t) 构造

可以看大,执行的结果如下:

$ curl -X GET http://localhost:8080/mono
Hello,Reactive Program

效果和SpringMVC 并无区别,同样的我们返回集合列表查看效果

    @GetMapping("/flux")public Flux<String> getFluxString() {String[] dataSet = new String[]{"This is 1", "This is 2", "This is 3", "This is 4"};return Flux.fromIterable(Arrays.asList(dataSet));}

分析过程

结果也和预期一致,那么不仅要思考了,同样和SpringMVC达到一致的效果,为什么我们要用WebFlux?

首先看着这两者并无区别,其实实际上和文章首页的架构图示一样,其底层核心的变了,实现接口,并再是基于Servlet,而是基于Http/Reactive Stream ,我们在接口方法添加参数

    @GetMapping("/flux")public Flux<String> getFluxString(HttpServerRequest request) {....}

此时访问flux接口,会报错

java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.http.HttpRequest

意思是非法的状态异常,没有org.springframework.http.HttpRequest的构造参数被发现,这说明WebFlux的实现已经不再是Serverlet了

实现Server Send Event

下面我是实现SSE(服务器推送),注意这里和Socket有所区别,Socket是双向通信,这是单向通信,由服务器向客户端推送消息

    @GetMapping(value = "/sse/object", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<Book> sseBook() {return Flux.interval(Duration.ofSeconds(1)).map(second ->new Book().setId(Stirng.valueOf(second)).setName("深入浅出Flux响应式Web编程" + second).setPrice("12")).take(5);}

模型Book需要lombok支持,没有的话,请手动完成set、get方法,并在Set方法尾部return this


@Data
@Accessors(chain = true)
public class Book {private String id;private String name;private String price;private Date createTime = new Date();
}

首先说明一下produces = MediaType.TEXT_EVENT_STREAM_VALUE 表示这是一个事件流,返回的是Flux类型,推送的间隔为1s,最后take(times)表示推送的次数,没有take表示无限流,times表示推送的次数,我们在shell中尝试调用下,看看效果

$ curl -X GET http://localhost:8080/sse/object
data:{"id":"0","name":"Flux响应式Web编程0","price":"12","createTime":"2018-09-09T12:46:10.445+0000"}data:{"id":"1","name":"Flux响应式Web编程1","price":"12","createTime":"2018-09-09T12:46:11.444+0000"}data:{"id":"2","name":"Flux响应式Web编程2","price":"12","createTime":"2018-09-09T12:46:12.444+0000"}data:{"id":"3","name":"Flux响应式Web编程3","price":"12","createTime":"2018-09-09T12:46:13.445+0000"}data:{"id":"4","name":"Flux响应式Web编程4","price":"12","createTime":"2018-09-09T12:46:14.444+0000"}

需要注意的是,在创建时间上,是每个1s钟由服务器推送过来的,这是和SpringMVC有着巨大的区别.

RouterFunctin 实现方式

Spring团队在实现WebFlux的有了另外的实现方式,利用RouterFuntion & HandleFunction,这里不做过多的赘述,这种方式的效果和上述效果一致,可以对比学习,代码如下:

向Spring容器中注入RouterFunctionBean对象

@Configuration
public class RouteConfig {@Beanpublic RouterFunction<ServerResponse> timeRoute(){return route(GET("/time"),TimeHandle::getTime).andRoute(GET("/sse"),TimeHandle::sendTimeWithSSE);}
}

具体逻辑实现

public class TimeHandle {private static SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");public static Mono<ServerResponse>  getTime(ServerRequest serverRequest){return ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(Mono.just(simpleDateFormat.format(new Date())),String.class);}// 实现时间SSE推送注意MediaType类型public static Mono<ServerResponse> sendTimeWithSSE(ServerRequest serverRequest){return  ok().contentType(MediaType.TEXT_EVENT_STREAM).body(Flux.interval(Duration.ofSeconds(1)).map(value -> simpleDateFormat.format(new Date())),String.class);}
}

整体来说还是比较简单的,请继续关注后期的WebFlux的学习过程~

参考文章

  • 【CSDN】(5)Spring WebFlux快速上手——响应式Spring的道法术器

  • 【IBM developerWorks】使用 Spring 5 的 WebFlux 开发反应式 Web 应用

转载于:https://www.cnblogs.com/zhoutao825638/p/10382275.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/449463.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django Rest Framework -解析器

基本代码结构 urls.py rom django.conf.urls import url, include from web.views.s5_parser import TestViewurlpatterns [url(rtest/, TestView.as_view(), nametest), ]views.py from rest_framework.views import APIView from rest_framework.response import Response f…

U盘版便携式Linux制作, casper-rw 解析

一直都在想&#xff0c;不管用谁的电脑&#xff0c;我都可以得到一个完全一致的工作环境&#xff0c;上面有我喜爱的软件&#xff0c;有我保存的重要资料&#xff0c;甚至浏览器的各种偏好都得一模一样&#xff01;现在的云计算技术可以部分解决这个问题&#xff0c;但是远远不…

canvas反向裁剪技巧

我们都知道在canvas 可以通过clip来实现剪裁功能&#xff0c;其步骤一般是先设置要裁剪的区域&#xff08;路径&#xff09;&#xff0c;然后通过ctx.clip()的实现裁剪&#xff0c;裁剪之后&#xff0c;后续的绘制只能在裁剪的区域显示效果&#xff0c;比如如下一段代码&#x…

set 和select 的区别

简单赋值是没有区别的 转载于:https://www.cnblogs.com/bingyizhihun/p/10597908.html

马上有钱:揭密25种成为有钱人的方法(图)

1、做你真正感兴趣的事—你会花很多时间在上面&#xff0c;因此你一定要感兴趣才行&#xff0c;如果不是这样的话&#xff0c;你不愿意把时间花在上面&#xff0c;就得不到成功。 2、自己当老板。为别人打工&#xff0c;你绝不会变成巨富&#xff0c;老板一心一意地缩减开支&a…

无人承运平台系统流程图

转载于:https://www.cnblogs.com/procedureMonkey/p/10598052.html

年买笔记本的8个小技巧 最适合自己才最好(组图)

显然&#xff0c;智能手机和平板在一定程度上可以替代传统电脑&#xff0c;让我们可以随时随地上网、使用各种应用。不过&#xff0c;传统电脑也拥有它的不可替代性&#xff0c;比如移动办公、视频编辑、玩游戏&#xff0c;笔记本电脑可能是个更好的选择。 作为一种成熟的电脑…

基本变量和引用变量

基本数据类型作比较&#xff0c;值相等则相等&#xff0c;值不相等则不相等&#xff08;忽略数据类型&#xff09; 引用类型作比较&#xff0c;引用地址相等则相等&#xff0c;否则都是不等的。 基本数据类型&#xff0c;和引用数据类型作比较&#xff0c;是比较值是否相等&…

[云框架]KONG API Gateway v1.5 -框架说明、快速部署、插件开发

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 当前版本采用KONGv0.12.3 当我们决定对应用进行微服务改造时&#xff0c;应用客户端如何与微服务交互的问题也随之而来&#xff0c;毕竟…

python 游戏 —— 汉诺塔(Hanoita)

一、汉诺塔问题 1. 问题来源 问题源于印度的一个古老传说&#xff0c;大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定&#xff0c;在小圆…

error: failed to push some refs to 'https://gitee.com/xxx/xxx'

一开始以为是本地版本和线上的差异 果断先直接pull 之后 还是不对,哎 不瞎搞了 搜... 获得消息: git pull --rebase origin master 原来如此:是缺失了文件 转载于:https://www.cnblogs.com/G921123/p/10605956.html

DevOps团队结构类型汇总:总有一款适合你

前言 组织中任何DevOps工作的主要目标都是改进客户和业务的价值交付&#xff0c;而不是降低成本、提升自动化或者通过配置管理驱动一切&#xff1b;这意味着&#xff0c;为了实现有效的Dev和Ops协同&#xff0c;不同的组织可能需要不同的团队结构。 概述 具体哪种DevOps团队结构…

magic

转载于:https://www.cnblogs.com/P201821430028/p/10611080.html

Vue 后台管理

这里是结合vue和element快速成型的一个demo 里面展示了基本的后台管理界面的大体结构和element的基本操作 GitHub的地址&#xff1a;https://github.com/wwwming/adminDemo 转载于:https://www.cnblogs.com/wangming1002/p/10613014.html

Linux查看MySQL版本的四种方法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1 在终端下执行 mysql -V 2 在help中查找 mysql --help |grep Distrib 3 在mysql 里查看 select version() 4 在mysql 里查看 status…

行业指数动量策略+akshare

以周为单位&#xff0c;获取本周最强的5只行业指数&#xff0c;进行均值购买。 数据源采用akshare。 导入包 import akshare as ak import pandas as pd import numpy as np import matplotlib 日线换为周线 #日线换为周线数据 def transferToWeekLine(df):data1dfstock_da…

2019-03-28 SQL Server Pivot

--现在我们是用PIVOT函数将列[WEEK]的行值转换为列&#xff0c;并使用聚合函数Count(TotalPrice)来统计每一个Week列在转换前有多少行数据&#xff0c;语句如下所示 select * from ShoppingCart as C PIVOT(count(TotalPrice) FOR [Week] IN([1],[2],[3],[4],[5],[6],[7])) AS…

C/C++开发者必不可少的15款编译器+IDE

摘要&#xff1a;C/C这两门语言依然活跃在编程领域里&#xff0c;其不仅拥有强大的功能集&#xff0c;而且还提供了强大的安全保障。为此&#xff0c;笔者专为C/C编码者收集了15款令人印象深刻的IDE和编译器。 Web开发者可选择的编程语言有很多比如&#xff0c;Java、.Net、PH…

白山云科技 CTO 童剑:空降后,如何有技术又有艺术地破局?

TGO 鲲鹏会北京分会举行了一场线下分享活动——《 CTO 空降如何平稳落地 》&#xff0c;白山云科技&#xff08;下称“白山”&#xff09;CTO 童剑分享了他的故事和经验。在工作中&#xff0c;“空降”这个问题不仅仅是 CTO 会遇到&#xff0c;每一个带团队的领导都会遇到。如何…

如何理解指向指针的指针?

本文由 伯乐在线 - 菜鸟浮出水 翻译自 StackOverflow。欢迎加入 技术翻译小组。转载请参见文章末尾处的要求。问题&#xff1a;如何理解指向指针的指针&#xff1f; 我在一篇教程中看到下面这段&#xff0c;它描述指向指针的指针是如何运作的。 引用文章相关段落如下&#x…