范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

高并发编程系列之Netty事件传播机制源码分析

  1 Pipeline的事件传播机制
  上一节中,我们已经知道AbstractChannelHandlerContext中有Inbound和Outbound两个boolean变量,分别用于标识Context所对应的Handler的类型。
  (1)Inbound为true时,表示其对应的ChannelHandler是ChannelInboundHandler的子类。
  (2)Outbound为true时,表示其对应的ChannelHandler是ChannelOutboundHandler的子类。
  大家肯定还有很多疑惑,不知道这两个属性到底有什么作用?这还要从ChannelPipeline的事件传播类型说起。Netty中的传播事件可以分为两种:Inbound事件和Outbound事件。如下是Netty官网针对这两个事件的说明。
  由上可以看出,Inbound事件和Outbound事件的流向是不一样的,Inbound事件的流向是从下至上的,而Outbound恰好相反,是从上到下。并且Inbound方法是通过调用相应的ChannelHandlerContext.fireIN_EVT()方法来传递的,而Outbound方法是通过调用ChannelHandlerContext.OUT_EVT()方法来传递的。例如:ChannelHandlerContext的fireChannelRegistered()调用会发送一个ChannelRegistered的Inbound给下一个ChannelHandlerContext,而ChannelHandlerContext的bind()方法调用时会发送一个bind的Outbound事件给下一个ChannelHandlerContext。
  Inbound事件传播方法的代码如下。
  Outbound事件传播方法的代码如下。
  我们发现:Inbound类似于事件回调(响应请求的事件),而Outbound类似于主动触发(发起请求的事件)。注意,如果我们捕获了一个事件,并且想让这个事件继续传递下去,那么需要调用Context对应的传播方法fireXXX()方法。
  如上面的代码所示,MyInboundHandler收到了一个channelActive事件,它在处理后,如果希望将事件继续传播下去,那么需要接着调用ctx.fireChannelActive()方法。
  接下来我们可以用一个代码案例来了解一下Pipeline的传播机制。我们分别编写InboundHandlerA、InboundHandlerB、InboundHandlerC和OutboundHandlerA、OutboundHandlerB、OutboundHandlerC类。
  InboundHandlerA的代码如下。
  InboundHandlerB的代码如下。
  InboundHandlerC的代码如下:
  以上代码中InboundHandlerA、InboundHandlerB、InboundHandlerC都调用了ctx.fireChannelRead()方法向下传播。
  OutboundHandlerA的代码如下。
  OutboundHandlerB的代码如下。
  OutboundHandlerC的代码如下。
  以上代码中OutboundHandlerA、OutboundHandlerB、OutboundHandlerC都调用了ctx.write()方法输出。
  下面我们编写测试代码,来了解其传播顺序。先是编写服务端代码。
  PipelineServer类主要完成Pipeline的注册工作,代码如下。
  PipelineClient类,与服务端建立连接并向服务端发送数据,代码如下。
  ClientInHandler类,完成向服务端发送数据的动作,代码如下。
  接下来,我们运行测试代码,分别启动PipelineServer和PipelineClient,得到的运行结果如下图所示。
  我们再尝试调整PipelineServer中Handler的注册顺序,代码如下。
  调整代码后,执行结果如下图所示。
  从执行结果上看,我们已经知道了Handler的传播顺序:从Inbound开始顺序执行,然后从Outbound逆序执行。1.1 Outbound事件传播方式
  Outbound事件都是请求事件(Request Event),即请求某件事情的发生,然后通过Outbound事件进行通知。
  Outbound事件的传播方向是从Tail到customContext再到Head。
  下面我们以Connect事件为例,分析一下Outbound事件的传播机制。
  首先,当用户调用了Bootstrap的connect()方法时,就会触发一个Connect请求事件,此调用会触发调用链,如下图所示。
  继续跟踪,我们就发现AbstractChannel的connect()方法其实又调用了DefaultChannelPipeline的connect()方法,代码如下。
  而pipeline.connect()方法的实现代码如下。
  可以看到,当Outbound事件(这里是Connect事件)传递到Pipeline后,其实是以Tail为起点开始传播的。
  而tail.connect()调用的是AbstractChannelHandlerContext的connect()方法。
  顾名思义,findContextOutbound()方法的作用是以当前Context为起点,向Pipeline中Context双向链表的前端寻找第一个Outbound属性为true的Context(即关联ChannelOutboundHandler的Context),然后返回。findContextOutbound()方法的实现代码如下。
  当我们找到了一个Outbound的Context后,就调用它的invokeConnect()方法,这个方法会调用Context关联的ChannelHandler的connect()方法,代码如下。
  如果用户没有重写ChannelHandler的connect()方法,那么会调用ChannelOutboundHandlerAdapter的connect()方法,代码如下。
  我们看到,ChannelOutboundHandlerAdapter的connect()方法仅仅调用了ctx.connect(),而这个调用又回到了Context.connect()方法调用Connect.findContextOutbound()方法,然后调用next.invokeConnect()方法,其次调用handler.connect()方法,最后又调用Context.connect()方法,如此循环下去,直到Connect事件传递到DefaultChannelPipeline的双向链表的头节点,即Head中。为什么会传递到Head中呢?回想一下,Head实现了ChannelOutboundHandler,因此它的Outbound属性是true。
  因为Head本身既是一个ChannelHandlerContext,又实现了ChannelOutboundHandler接口,所以当connect()消息传递到Head后,会将消息传递到对应的ChannelHandler中处理,而Head的handler()方法返回的就是Head本身,代码如下。
  因此最终Connect事件是在Head中被处理的。Head的Connect事件处理逻辑的代码如下。
  到这里,整个Connect请求事件就结束了。下图描述了整个Connect请求事件的处理过程。
  我们仅仅以Connect请求事件为例,分析了Outbound事件的传播过程,但是其实所有的Outbound的事件传播都遵循着一样的传播规律,小伙伴们可以试着分析一下其他Outbound事件,体会一下它们的传播过程。1.2 Inbound事件传播方式
  Inbound事件和Outbound事件的处理过程是类似的,只是传播方向不同。
  Inbound事件是一个通知事件,即某件事已经发生了,然后通过Inbound事件进行通知。Inbound通常发生在Channel的状态改变或I/O事件就绪时。
  Inbound的特点是其传播方向从Head到customContext再到Tail。
  上面我们分析了connect()方法其实是一个Outbound事件,那么接着分析Connect()事件后会发生什么Inbound事件,并最终找到Outbound和Inbound事件之间的联系。当Connect()事件传播到Unsafe后,其实是在AbstractNioUnsafe的connect()方法中进行处理的,代码如下。
  在AbstractNioUnsafe的connect()方法中,先调用doConnect()方法进行实际的Socket连接,当连接后会调用fulfillConnectPromise()方法,代码如下。
  我们看到,在fulfillConnectPromise()方法中,会通过调用pipeline().fireChannelActive()方法将通道激活的消息(即Socket连接成功)发送出去。而这里,当调用pipeline.fireXXX后,就是Inbound事件的起点。因此当调用pipeline().fireChannelActive()方法时,就产生了一个ChannelActive Inbound事件,接下来看一下Inbound事件是怎么传播的,代码如下。
  果然,在fireChannelActive()方法中调用了head.invokeChannelActive()方法,因此可以证明Inbound事件在Pipeline中传输的起点是Head。head.invokeChannelActive()方法的代码如下。
  上面的代码应该很熟悉了。回想一下在Outbound事件(例如Connect事件)的传输过程中,我们也有类似的如下操作。
  (1)首先调用findContextInbound(),从Pipeline的双向链表中找到第一个Inbound属性为true的Context,然后将其返回。
  (2)调用Context的invokeChannelActive()方法,invokeChannelActive()方法的代码如下。
  这个方法和Outbound的对应方法(如invokeConnect()方法)如出一辙。与Outbound一样,如果用户没有重写channelActive()方法,就会调用ChannelInboundHandlerAdapter的channelActive()方法,代码如下。
  同样地,在ChannelInboundHandlerAdapter的channelActive()方法中,仅仅调用了ctx.fireChannelActive()方法,因此就调用Context.fireChannelActive()方法,其次调用Connect.findContextInbound()方法,然后调用nextContext.invokeChannelActive()方法,再然后调用nextHandler.channelActive()方法,最后调用nextContext.fireChannelActive()方法,如此循环。同理,Tail本身既实现了ChannelInboundHandler接口,又实现了ChannelHandlerContext接口,因此当channelActive()消息传递到Tail后,会将消息传递到对应的ChannelHandler中处理,而Tail的handler()方法返回的就是Tail本身,代码如下。
  因此ChannelActive Inbound事件最终是在Tail中处理的,我们看一下它的处理方法。
  TailContext的channelActive()方法是空的。大家自行查看TailContext的Inbound处理方法时会发现,它们的实现都是空的。可见,如果是Inbound,当用户没有实现自定义的处理器时,那么默认是不处理的。下图描述了Inbound事件的传输过程。
  1.3 小结
  Outbound事件为传播过程总结如下。
  (1)Outbound事件是请求事件(由Connect发起一个请求,并最终由Unsafe处理这个请求)。
  (2)Outbound事件的发起者是Channel。
  (3)Outbound事件的处理者是Unsafe。
  (4)Outbound事件在Pipeline中的传输方向是从Tail到Head。
  (5)在ChannelHandler中处理事件时,如果这个Handler不是最后一个Handler,则需要调用ctx的方法(如ctx.connect()方法)将此事件继续传播下去。如果不这样做,那么此事件的传播会提前终止。
  (6)Outbound事件的传播方向是,从Context.OUT_EVT()方法到Connect.findContextOutbound()方法,再到nextContext.invokeOUT_EVT()方法,再到nextHandler.OUT_EVT()方法,最后到nextContext.OUT_EVT()方法。
  Inbound事件传播过程总结如下。
  (1)Inbound事件为通知事件,当某件事情已经就绪后,会通知上层。
  (2)Inbound事件的发起者是Unsafe。
  (3)Inbound事件的处理者是Channel,如果用户没有实现自定义的处理方法,那么Inbound事件默认的处理者是TailContext,并且其处理方法是空实现。
  (4)Inbound事件在Pipeline中的传输方向是从Head到Tail。
  (5)在ChannelHandler中处理事件时,如果这个Handler不是最后一个Handler,则需要调用ctx.fireIN_EVT()方法(如ctx.fireChannelActive()方法)将此事件继续传播下去。如果不这样做,那么此事件的传播会提前终止。
  (6)Intbound事件的传播方向是,从Context.fireIN_EVT()方法到Connect.findContextInbound()方法,再到nextContext.invokeIN_EVT()方法,再到nextHandler.IN_EVT()方法,最后到nextContext.fireIN_EVT()方法。
  由此可知,Outbound事件和Inbound事件在设计上十分相似,并且Context与Handler之间的调用关系也容易混淆,因此我们在阅读这里的代码时,需要特别注意。

阿根廷铁卫飞身堵枪眼,裁判胡乱判点!另1镜头更令梅西欣喜北京时间今天凌晨,在欧联杯小组首轮比赛中,曼联坐镇主场迎战皇家社会。这场比赛,曼联15次射门,没能取得进球,皇社8次射门,罚中1粒点球。最终曼联史无前例地01输球,欧战遭遇开门黑。碧桂园最后的底牌出品子弹财观作者荷默编辑蛋总美编倩倩在房地产行业进入调整期以来,众多知名房企都遭遇了营收和市值的断崖式下跌,作为行业龙头之一的碧桂园还能扛多久?9月9日,碧桂园公告称将发行面值15比亚迪们,加速围堵造车新势力进入9月以来,车企相继公布8月造车成绩单。通过公开的数据来看,新势力车企已经在市场定位和销量表现上走出明显分化,哪吒零跑等品牌大有后来居上之势,蔚来理想们正处于朝多产品矩阵阶段过渡下周三油价降价已成定局,第七次降价要来了,9月16日2022年国内成品油零售价第18轮调整将在9月21日24点(下周三晚)启动,原油价格反转下跌近4按今天第7个工作日数据预测为油价降价且降价已成定局,当前原油变化率6。41,国内汽柴男星参展上艳压热搜,王鹤棣穿貂热得吐舌,朱一龙高领毛衣套夹克饿了吗?戳右边关注我们,每天给您送上最新出炉的娱乐硬核大餐!9月16日,内娱又有新的时尚展了,不过令人捧腹的是,这次男明星们登上了艳压的热搜,还是热搜榜的第一。更幽默的是,点开艳压查尔斯的厄运还没结束国王没有那么好当的。立华我讲过一次,领导看起来有权,那建立在领导帮手下的时候,换句话说,只有以权谋私,用权力帮手下人实现私人欲望的时候,领导才大权在握。这时候的权不在领导的手里,在经典唯美的句子说说,简短又随心所欲一沉眠在旧时光旧回忆,你懵然地闯进我的梦境。二花碎,叶落散,花飞花落花灿烂。三你为了她,连习惯都可以改变,是谁给的坚强。四我不能忍受活着。不喜欢的姿态。五有些事,不谈是个结,谈开了如何让双眼更传神?当我们觉得眼袋影响到美观的时候,有一些求美者会选择借助医学美容手段,来祛除眼袋,那么哪种方式是更加有效的?武汉协和医院整形外科副主任医师钟爱梅9月9日做客湖北生活广播健康快车道,为痘痘反复不见好怎么办?大家在社交圈真的越来越好看了因为有了轻颜相机美图秀秀的强强助攻即使碰上皮肤状态不好,爆痘烂脸时都可以用滤镜磨皮来解决肌肤危机但真实的皮肤问题还真真切切的存在在社交圈光鲜亮丽,现实中想象得到么?34岁牙医就拥有5只爱马仕包包不知是谁传出来的,似乎大家都知道牙科医生非常有钱!这次来看看这位年轻有为的牙医是否惊掉你的下巴。先看看她的5支爱马仕。办公桌的是爱马仕Roulisminibag,5万块左右。红色搭莫克丽肤如何去掉讨厌的黑眼圈黑眼圈是每个人都曾经经历过的,形成黑眼圈的原因有很多,比如睡眠不足思虑过度熬夜甚至饮食不正常都有可能造成黑眼圈。一旦有了黑眼圈,整个人看起来就会无精打采,给人以精力不济的印象,所以
朱元璋曾是张无忌手下,朱元璋当上皇帝后,张无忌下场是如何金庸老爷子已经仙逝,余下的武侠小说依旧在熠熠生辉。他的小说之所以能够长盛不衰,是因为其中巧妙融合了史实和虚构,使得人物行走在虚实之间,摇曳出迷人的姿态。张无忌就是一个典型,他有着普与总冠军擦肩而过,篮网从三巨头时代坠入尘埃当詹姆斯哈登抵达布鲁克林,与杜兰特,欧文组成三巨头那一刻,仿佛篮网离总冠军只有一步之遥了。事实上他们的确曾经离总冠军如此之近,在20202021赛季季后赛首轮用五场比赛淘汰了波士顿大爆冷!世界冠军03惨败,平野美宇崩盘,张本美和险胜国乒名将北京时间2月12日,乒乓球T联赛爆出大冷门,世界冠军名将平野美宇遭遇03惨败,输给了二线选手森樱花,而她所在的神奈川俱乐部不得不靠14岁小将张本美和才拿了2分包括险胜国乒名将李佳燚中国球员掀起海外留洋浪潮,但李莹莹却成了最惨的一个中国球员掀起海外留洋浪潮,但李莹莹却成了最惨的那一个。截止目前20222023赛季中国球员海外留洋人数已达18人之多,创历史之最。女排方面朱婷领衔姚迪缪伊文任凯懿王思敏李雨薇车文涵里夫斯谈被肘击说明我不是很聪明吧,我总是被人打到脸今日,湖人109103客场击败勇士。赛后,湖人后卫奥斯汀里夫斯接受了采访。谈到他被乔纳森库明加肘击导致面部受伤,里夫斯说这说明我不是很聪明,我总是被人打到脸。我不知道,我就是努力在北京女足全锦赛开门红,3主力离队阵容有隐忧2月12日,全国女足锦标赛(以下简称全锦赛)在昆明海埂基地打响。北京女足首战告捷,以4比0战胜女甲球队武汉青山武体女足。取得开门红的同时,北京女足仍有隐忧,主帅于允接受新京报记者采ampampquot情绪价值ampampquot越高的父母,越容易培养出幸福感强的孩子!作者慢热的喜来源新东方家庭教育(IDxdfjtjy)被忽视的孩子一书中有这样一段话孩子的情绪就像是流动的水,源头就是他的内心,如果在水前设置了障碍,水要么绕过障碍,改变流动的方向,四季不落幕,北京室内滑雪馆见证冰雪运动从冷门到大众不同于露天滑雪场,室内的滑雪馆打破了季节天气的限制,让滑雪成为一项四季运动。立春后的北京,位于顺义区的乔波滑雪馆人气不减,2月11日,临近中午时分,不少滑雪爱好者在雪道上穿梭滑行。北京冬奥一周年,羽生结弦,转身向前,从未离开!现在回头看,一切似乎早已有迹可循。2022年2月20日,北京冬奥花样滑冰Gala表演滑的最后,摄影机拍摄到了这样的画面离场前的羽生结弦如常地低头触冰,起身时他久久凝视,然后带着微笑网友在美国偶遇杨澜!素颜出镜气色好,54岁鬓角斑白模样大变近日,有网友在社交平台上晒出自己在美国纽约偶遇央视知名主持人杨澜,并晒出两人的合照,也是曝光了杨澜的近况,而且此次杨澜现身美国可不止被一位网友偶遇,许多网友都在不同的时间段偶遇到了北京大学发讣告据北京大学生命科学学院讣告,著名细胞生物学家杰出的教育家,中国科学院院士,北京大学教授翟中和,于2月10日14时42分在京逝世,享年93岁。南都记者了解到,翟中和是中国细胞生物学和