响应式编程之Reactor-Netty

前言

上文讲到使用WebFlux(spring-boot-starter-webflux),我们的接口可以这么写

@GetMapping("/user")
public Mono<String> getUser() { 
    return Mono.just("pq"); 
}

细想一下,而我们的接口返回了一个Mono/Flux的发布器,而接口调用后的结果确实订阅了这个发布器之后推送的结果:“pq”, 很显然是WebFlux帮我们进行了订阅,并把订阅的结果返回给响应流中

那么WebFlux到底是如何做的呐?今天就以这个问题为出发点研究一下WebFlux的源码

Reactor Netty

WebFlux可以像Spring MVC运行在Tomcat上,同时也可以运行在非Servlet的服务例如Netty上

一般情况下我们使用SpringBoot不需要考虑这些事情,只需引入spring-boot-starter-webflu即可,而此时默认WebFlux就是运行在Netty之上的,很显然作为一个响应式的服务使用Netty更加合理,因为Netty本来就是一个非阻塞的异步网络通讯框架

spring-boot-starter-webflu依赖中,内部包含一个依赖:reactor-netty,这个东西的就是Reactor及Netty的结合,使用它你可以快速搭建一个响应式版http服务(也支持websocket,tcp,udp),新建一个项目试一下,代码如下

<dependency>
    <groupId>io.projectreactor.netty</groupId>
    <artifactId>reactor-netty</artifactId>
    <version>0.9.10.RELEASE</version>
</dependency>
public class ReactorNettyApplication {
    public static void main(String[] args) {
        DisposableServer server =
                HttpServer.create() // 创建http服务
                        .port(7892) // 绑定端口
                        .route(routes -> // 路由
                                routes.get("/hello", (request, response) -> {
                                        return response.sendString(Mono.just("Hello World"));
                                        }
                                )
                        )
                        .bindNow();
        server.onDispose()
                .block();
    }
}

访问一下

Hello

是不是很有Tomcat的感觉,我们的接口返回的就是Mono对象,而前端展示的是订阅后的数据“Hello World”,此时再看看我们要研究的课题,会发现实际上并不是WebFlux解决的,而是Reactor Netty解决的

那问题来了,WebFlux可以运行在Tomcat,Jetty,Netty,Undertow等,那么如果用的不是Netty,自然也不会引入Reactor Netty依赖,那么这个课题谁来解决?

实际上,在这个问题的角度,WebFlux相当于只是制定了规范,而Reactor Netty是使用Netty作为服务时的一种实现,其他的服务自然有对应的实现

那么我们就看看Reactor Netty是如和把Mono对象的发布内容返回给响应的,其实想一想很简单,不过就是订阅一下,并在回调中把数据写回个客户端的Channel,但我还是想看看代码到底怎么具体写的

以下源码讲解需要对Netty非常熟悉,想深入可以参照下netty源码,但这篇文章是讲源码,这里只要会用就可以了

首先reactor-netty在启动netty服务时,定制了一个Handler,即ChannelOperationsHandler

ChannelOperationsHandler

ChannelOperationsHandler在接收到请求时,会执行到ChannelOperations的onInboundNext方法

channelRead

该方法最终会走向HttpServerHandle下的onStateChange监听方法

HttpServerHandle.onStateChange

onStateChange方法中开始执行hander.apply(ops, ops),并开始订阅,此时发布者开始发布

这个hander.apply就是根据路由执行我们的用户代码,即路径“/hello”绑定的方法

/hello

再看一下我们的代码执行了response.sendString,这个方法最终会走向send方法,看看send方法里做了什么

send

使用flatMap加入了一个中间处理,而处理的方式就是channel().writeAndFlush(msg),此时当发布者发布数据时,就会回调执行writeAndFlush,即将结果写回响应,一次http请求就完成了!

Spring WebFlux

说了这么久reactor-netty,活都让它干了,那么WebFlux干了什么呐又?

使用reactor-netty我们的服务就是运行在netty之上,而WebFlux提供了一个统一的响应式web开发框架,让基于WebFlux响应式程序可以自由运行在netty,tomcat,jetty,Undertow之上

如果这句话不好理解,可以类比一下Java语言,Java语言之所以可以跨平台(运行在windows,linux)之上,是因为java可以再不同的平台上通过jvm适配为不同的、适应该平台的语言,我们写一份代码,就可以让其运行在windows,linux...上,这就是为什么java被称为高级语言

同理,WebFlux可以称作响应式的高级框架,使用WebFlux开发程序,只要写一份,就可以让它运行在netty,tomcat,jetty,Undertow...上,这是因为我们相当于只写了一个服务的抽象,而底层WebFlux内部有不同的适配器去适配不同的实现,比如

  • 如果想运行在netty上,WebFlux提供ReactorHttpHandlerAdapter适配器,将我们的代码适配到reactor-netty的实现

  • 如果想运行在Tomcat上,同样的代码,WebFlux提供TomcatHttpHandlerAdapter适配器,将我们的代码适配tomcat-embed-core的实现

image.png

同时,WebFlux是Spring开发的,所以框架的使用我们可以沿用原来的@Controller、@GetMapping等注解,让我们用最熟悉的方式来写响应式代码。

WebFlux也是响应式Web开发的一个基础框架,背后对应的是响应式生态,是一整套响应式开发的解决方案

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容