浅析netty是如何将各种ChannelHandler跟不同的事件绑定起来的

netty使用的是事件驱动模型,在ChannelPipeline中绑定了各种的ChannelHandler,分为ChannelInBoundHandler和ChannelOutBoundHandler,分别处理进站的信息流和出站的信息流。

用户自己实现对应的接口或继承对应的Adapter类,注册对应的事件之后,就可以将这个hander加入到ChannelPipeline中,当管道中发生了该事件之后,用户自己的handler就会处理这个进站或出站的消息。

实际上,加入到ChannelPipeline中的handler最后会组成一个链表,每当产生一个事件时,netty都会遍历这个链表,在其中找到注册过这个事件的handler,并调用handler的方法进行处理。

 

 图中为AbstractChannelHandlerContext类中处理ChannelActive事件的代码,可以看到它首先调用findContextInbound方法寻找下一个处理ChannelActived事件的Context并继续调用fireChannelActive方法,将事件往下传递。

 

 在findContextInbound方法中,通过一个while循环便利这个链表,找到同mask位运算不为0的Context并返回,我们在看看常量MASK_CHANNEL_ACTIVE定义的位置

 

可以看到 MASK_CHANNEL_ACTIVE即1左移三位变成二进制的1000,但是上图中的executionMask又是哪来的呢?跟踪代码发现,在构造函数中最终会调用 ChannelHandlerMask的mask0方法,

 

如果是InboundHandler 先将mask赋值为111111111,然后判断是否要跳过特定的方法,如果跳过,则将对应事件的编码取反再和mask进行位与计算,比如跳过MASK_CHANNEL_REGISTERED事件,

则MASK_CHANNEL_REGISTERED取反后11111111111111111111111111111101,与上111111111最后得到的mask为111111101,此即为executionMask的值。在判断需要处理的事件时,用此值与上对应的事件编码,即可通过位运算快速判断是否需要处理。

如,此时用111111101与上MASK_CHANNEL_REGISTERED的编码10得到0,则满足while条件,继续遍历,与上事件MASK_CHANNEL_UNREGISTERED的编码100得100不为0,则返回链表中该handler并调用该handler的对应事件方法

 

posted @ 2021-09-03 17:55  cloxi  阅读(591)  评论(0)    收藏  举报