各位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的新特性之后,内心五味杂陈的我,只能用一个表情来形容:

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

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

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() { //1
return 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 { @Bean
public 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的学习过程~

参考文章

Spring WebFlux 响应式编程学习笔记(一)的更多相关文章

  1. springboot2 webflux 响应式编程学习路径

    springboot2 已经发布,其中最亮眼的非webflux响应式编程莫属了!响应式的weblfux可以支持高吞吐量,意味着使用相同的资源可以处理更加多的请求,毫无疑问将会成为未来技术的趋势,是必学 ...

  2. [转]springboot2 webflux 响应式编程学习路径

    原文链接 spring官方文档 springboot2 已经发布,其中最亮眼的非webflux响应式编程莫属了!响应式的weblfux可以支持高吞吐量,意味着使用相同的资源可以处理更加多的请求,毫无疑 ...

  3. SpringBoot使用WebFlux响应式编程操作数据库

    这一篇文章介绍SpringBoot使用WebFlux响应式编程操作MongoDb数据库. 前言 在之前一篇简单介绍了WebFlux响应式编程的操作,我们在来看一下下图,可以看到,在目前的Spring ...

  4. SpringBoot 2.x (14):WebFlux响应式编程

    响应式编程生活案例: 传统形式: 一群人去餐厅吃饭,顾客1找服务员点餐,服务员把订单交给后台厨师,然后服务员等待, 当后台厨师做好饭,交给服务员,经过服务员再交给顾客1,依此类推,该服务员再招待顾客2 ...

  5. Spring 5 响应式编程

    要点 Reactor 是一个运行在 Java8 之上的响应式流框架,它提供了一组响应式风格的 API 除了个别 API 上的区别,它的原理跟 RxJava 很相似 它是第四代响应式框架,支持操作融合, ...

  6. 07-Spring5 WebFlux响应式编程

    SpringWebFlux介绍 简介 SpringWebFlux是Spring5添加的新模块,用于Web开发,功能和SpringMvc类似的,WebFlux使用当前一种比较流行的响应式编程框架 使用传 ...

  7. CSS响应式布局学习笔记(多种方法解决响应式问题)

    在做web开发的工作中,会遇到需要我给页面根据设计的要求,进行响应式布局,这里跟大家分享下我对于响应式布局的解决方法: 我主要利用的是CSS3 媒体查询,即media queries,可以针对不同的媒 ...

  8. spring AOP面向切面编程学习笔记

    一.面向切面编程简介: 在调用某些类的方法时,要在方法执行前或后进行预处理或后处理:预处理或后处理的操作被封装在另一个类中.如图中,UserService类在执行addUser()或updateUse ...

  9. Spring中AOP切面编程学习笔记

    注解方式实现aop我们主要分为如下几个步骤: 1.在切面类(为切点服务的类)前用@Aspect注释修饰,声明为一个切面类. 2.用@Pointcut注释声明一个切点,目的是为了告诉切面,谁是它的服务对 ...

随机推荐

  1. 面试前必须知道的MySQL命令【explain】

    前言 只有光头才能变强 刷面试题的时候,不知道你们有没有见过MySQL这两个命令:explain和profile(反正我就见过了).. 之前虽然知道这两个命令大概什么意思,但一直没有去做笔记.今天发现 ...

  2. python中的del

    python中的del,只删除变量,不删除数据,具体表现为: a=1,c=a,del a,(c=1) 和 a = [1,2,3,4,5] b= a[0] del a[0] print a ([2,3, ...

  3. 基于CNN的人群密度图估计方法简述

    人群计数的方法分为传统的视频和图像人群计数算法以及基于深度学习的人群计数算法,深度学习方法由于能够方便高效地提取高层特征而获得优越的性能是传统方法无法比拟的.本文简单了秒速了近几年,基于单张图像利用C ...

  4. C#EF中,使用类似于SQL中的% 模糊查询

    最近在做项目的时候需要使用到模糊查询,但是后台使用EF写的 而不是ADO或者是Dapper,如果是这样的话,我们就可以使用Sql语句直接进行模糊查询 现在我们需要在LINQ中使用类似于模糊查询 在EF ...

  5. Hello World 程序的起源与历史

    这是一个最著名的程序.对每一位程序员来说,这个程序几乎是每一门编程语言中的第一个示例程序.那么,这个著名的程序究竟从何而来呢? 实际上,这个程序的功能只是告知计算机显示 Hello World 这句话 ...

  6. Mac OS X中开启或关闭显示隐藏文件命令

    前言:之前一直用的都是 windows 系统的电脑,刚接触 Mac ,很多功能都不熟悉,写下博客记录一下,以防以后忘记,也给后来者提供方便. 命令行方式:显示隐藏文件: defaults write ...

  7. Android中对已安装应用的管理实现

    获取.管理手机中已安装的所有应用信息 1.创建应用的实体类AppInfo,属性有应用的名称.包名.图标.第一次安装时间和版本名称 public class AppInfo { private Stri ...

  8. css 选择器基础

    有时在看别人代码时,看到一长串的选择器经常有点懵,今天来夯实一下基础 选择器有: 1.标签选择器 :就是HTML 中的标签 如<p> <h1> <body>等 2. ...

  9. V8引擎的垃圾回收策略

    V8 的垃圾回收策略主要基于分代式垃圾回收机制.所谓分代式,就是将内存空间分为新生代和老生代两种,然后采用不同的回收算法进行回收. 新生代空间 新生代空间中的对象为存活时间较短的对象,大多数的对象被分 ...

  10. Vue(day4)

    这里说的Vue中的路由是指前端路由,与后端路由有所区别.我们可以使用url来获取服务器的资源,而这种url与资源的映射关系就是我们所说的路由.对于单页面程序来说,我们使用url时常常通过hash的方法 ...