Spring Boot2.0之WebFlux开发实战(含源码)

作者|刘海东

编辑|哧溜君、隳天

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

15分钟和你一起聊一聊2.2万星超热门开源项目Spring Boot 2.0之WebFlux开发,从技术介绍、开发教程、集成案例演示到示例源代码,一网打尽。

 

一、 背景知识

1.1 Spring Boot2.0

北京时间3月1日,Spring Boot 2.0正式发布Release版本。作为Spring生态中重要的开源项目,Spring Boot旨在帮助开发者更容易的创建基于Spring的应用程序和服务。经历了4年的发展,Spring Boot已经拥有了22000多star,16000次Commits,贡献者超过400多名的超热门开源项目。

其中刚发布的2.0版本是自2014年4月1日发布的1.0版本以来第一次重大修订,也是首个提供对Spring Framework 5.0支持的GA稳定版本,2.0带来了很多新的特性

✓基于Spring 5构建的Spring Boot 2.0,通过使用Spring WebFlux 提供了响应式Web编程支持;

✓基于Java 8(最低标准),支持Java 9;

✓支持HTTP/2;

Spring Boot的Web容器选择中Tomcat、Undertow和Jetty均已支持HTTP/2。HTTP/2较HTTP/1.1在性能上有显著提升,页面加载时间降低了50%,详见Java 9和Spring Boot2.0纷纷宣布支持的HTTP/2到底是什么

其余新特性不在此赘述,详见Spring Boot 2.0 Release Notes

1.2 Spring WebFlux

Spring WebFlux是一个非阻塞的函数式Reactive Web框架,可以用来构建异步的、非阻塞的、事件驱动的服务,在伸缩性方面表现非常好。名称中的Flux来源于Reactor中的类Flux。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

众所周知Spring MVC是同步阻塞的IO模型,资源浪费相对比较严重,当我们在处理一个耗时的任务时,例如上传一个较大的文件时,服务器的线程一直在等待接收文件,这期间什么也做不了,等到文件接收完毕可能又要写入磁盘,写入的过程线程又只能在那等待,非常浪费资源。而Spring WebFlux是这样做的,线程发现文件还没接收好,先去做其他事情,当文件接收完毕后通知该线程来处理,后续写入磁盘完毕后再通知该线程来处理,通过异步非阻塞机制节省了系统资源,极大的提高了系统的并发量。因此对于微服务下的IO密集型的Service来说,WebFlux是一个不错的选择。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

Spring WebFlux与Spring MVC框架对比(一)

 

左边是传统基于Servlet的Spring Web MVC框架,右边是Spring Framework 5.0引入的基于Reactive Streams的Spring WebFlux框架,从上到下依次是Router Functions、WebFlux和Reactive Streams三个新的组件。

● Router Functions:对应@Controller、@RequestMapping等标准的Spring MVC注解,提供了一套函数式编程的API,用于创建Router、Handler和Filter。

● WebFlux:核心组件,用于协调上下游各个组件提供响应式编程的支持。

● Reactive Streams:一种支持Backpressure的异步数据流处理标准,主流实现有RxJava和Reactor,Spring、WebFlux默认集成的是Reactor。Backpressure是一种反馈机制,当数据的发布速度超过处理速度时,消费者需要决定缓存还是丢弃,在响应式编程中,决定权交回给了发布者,消费者只需根据自身处理能力向发布者请求相应数量的数据。

●Web容器:Spring WebFlux既支持Tomcat、Jetty等传统容器(前提是支持Servlet3.1+),又支持Netty、Undertow等异步容器。

只能运行在Servlet 3.1+容器上,是因为3.1规范支持异步处理,该功能主要针对业务处理较耗时的情况,可以减少服务器资源占用,提高并发处理速度。

 

二、 Spring WebFlux实战

2.1 WebFlux工程创建

本文默认开发环境是JDK8,开发工具是IntelliJ IDEA。

下面我们基于Spring Boot 2.0创建一个WebFlux工程,操作步骤非常简单:

1)点击Create New Project,创建一个新的项目;

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

2)选择Spring Initializr,并配置JDK版本为1.8,Initializr Service UR按默认配置为https://start.spring.io;

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

3)在metadata页配置工程包名等信息,其中type项目构建方式选择默认值,使用maven进行项目构建;

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

4)在Dependencies页,我们先将Spring Boot版本设置为2.0.0,可以看到下方有很多选项可以选择,每个选项代表一个组件,这里选择“Web”->“Reactive Web”组件。可以看到下方提示,Reactive Web development with Netty and Spring WebFlux,即通过Reactive Web构建一个WebFlux应用服务;

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

5)最后配置下工程名称和项目路径,即完成了Spring WebFlux应用的创建。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

默认的demo工程pom中只包括webflux和reactor等组件依赖。

2.2 Hello World应用开发

下面通过编写Handler和Router Functions来实现hello world程序。

1)编写Hello world handler,该类相当于Spring Web中的Service bean;

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

2)将Hello world handler注册到路由上,类似于Spring Web中的Controller类的创建。除了新的Router Functions接口,Spring WebFlux同时支持使用老的Spring MVC注解声明Reactive Controller。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

3)接着运行DemoApplication的main方法,即完成了服务启动,这里默认采用了Netty作为reactor的底层容器启动。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

最后访问http://127.0.0.1:8080/hello,返回hello world即表示服务启动和访问成功。

2.3 注册登录应用开发

需要注意目前支持reactive编程的数据库只有MongoDB,Redis,Cassandra,Couchbase,而JDBC与JPA的事务是基于阻塞IO模型的,并不是自然支持reactive编程风格,需要等待Spring Data Reactive升级IO模型才能支持相关数据库事务的使用。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

Spring WebFlux与Spring MVC框架对比(二)

 

这里以Redis作为数据库,实现一个简单的用户注册登录功能。

1)首先配置Spring Data Reactive Redis,默认指向本地6379端口的Redis;

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

2)编写用户注册登录handler,主要通过RedisConnection进行数据入库和查询操作,并将业务处理结果以Json格式进行返回。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

Uri中的参数可以通过ServerRequest.bodyToMono来获取。

返回的类型Mono可以通过ServerResponse来创建,主要包括以下几步:

a) 状态码方法,可以使用现成的也可以自定义,例如成功的状态码:

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

b) ContentType(MediaType var1)返回的内容类型是MediaType类型;

c) 最后是返回的内容:

184154_oukx_2969787.gif

一般常用body()来放入返回的内容,如使用BodyInserters的构建方法fromObject()。

3)添加注册登录路由,将url路由给具体的handler来进行处理;

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

路由关系创建主要通过RouterFunctions来创建route,

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1     其中RequestPredicate和HandlerFunction都是函数式接口,HandlerFunction接受一个ServerResponse的子类返回Mono,可以把这个对象认为是实际处理逻辑的部分。

下面我们来验证下程序的运行情况:

1)首先运行服务,然后通过postman发送用户注册请求;

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

 

2)发送注册请求后,除了前台返回{"message":"successful"},同时可以查看Redis中保存的注册信息;

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

3)接着用刚注册的信息发起登录请求,可以看出返回结果为登录成功。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

至此即完成了一个简单的基于Spring WebFlux和Redis的用户注册登录功能开发。

 

三、分析总结

通过以上介绍,可以看出基于SpringBoot进行WebFlux开发即简单又高效。下面对WebFlux中几个关键语法点进行介绍:

首先简单说下Reactor的两个关键概念,Mono和Flux是Reactor中的流数据类型,Mono是一个用来发送0或者单值数据的发布器,Flux可以用来发送0到 N 个值。它们表示在订阅这些发布服务时发送的数值流。

如下图中getUserById()返回一个Mono<User>表示其在数据可用的情况下发送0个或者单个用户,getUsers()返回一个用户列表的Flux实例,表示其发送0到多个用户数据。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

上文提到的handler处理类相当于服务bean,一般用来编写业务功能,其中返回的ServerResponse类似Spring Web中的ResponseEntity用来封装响应数据,包括状态码、HTTP头等信息,它包含了ok(),notFound()等方法,用来创建不同类型的响应信息。如上图的UserRepository.getUserById()返回一个Mono<User>,而ServerResponse.ok().body(Mono.just(user), User.class) 将这个Mono<User>转成Mono<ServerResponse>,这代表在ServerResponse可用时候发送响应的流。

ServerResponse.notFound().build()返回一个Mono<ServerResponse>对象,当给定的pathVariable中找不到对应用户信息时返回404的服务器响应信息。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

Spring WebFlux除了对响应式http的支持外,还包括服务端推送事件(Server Sent Events,SSE)、WebSocket客户端和服务端的支持。其中服务端推送事件允许服务器不断地推送数据到客户端,它的实现非常简单,只需要返回对象类型配置成Flux<ServerSentEvent>,就会自动按照SSE规范要求的格式发送响应。

在命令式的编程风格中,线程的执行会被堵塞,直到接收到数据。这使得数据在实际返回之前线程必须进行等待。而在Reactive编程中,我们定义了一个流,用来发送数据以及数据返回时所执行的操作。使用这种方法线程不会被堵塞的。当数据返回时框架会选择一个可用的线程进行下一步处理,这就体现出异步非阻塞模式的优势所在。因此响应式编程能带来更快处理速度,更高硬件利用率的未来选择。

 

微信公众号回复【webflux】获取示例代码,欢迎和作者一起交流,尤其欢迎女神!

 

参考资料

  • https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-fn-handler-functions

  • https://coyee.com/article/12086-spring-5-reactive-web

  • https://zhuanlan.zhihu.com/p/30813274

  • https://github.com/hantsy/spring-reactive-sample#spring-data-redis

  • https://www.ibm.com/developerworks/cn/java/spring5-webflux-reactive/index.html

作者介绍

刘海东,供职于开鑫金服,任移动端架构师、销售平台技术专家,主要方向是Java Web、Android、shell和C++,精力充沛,爱好广泛。

 

大神看这里 ↓↓↓↓

 

1、【招聘】青春还在,梦想要快,大神请接招!

2、答题送开年福利,就这么任性!!!

 

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

转载于:https://my.oschina.net/u/2969787/blog/1816236

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值