阅读 993

Netty中的ChannelHander详解

channelHandler是用来做什么的?ChannelHandler用来处理组件之间的交互,结合它的状态做各种业务,通过ChannelPipelinel来连接各个ChannelHandler

ChannelHandler怎么在实际中使用?

channelHandler家族具有如下的结构


  • ChannelInboundHandler用来处理入站数据以及各种状态变化。ChannelInboundHandlerAdapter对接口做适配,默认简单的提交到ChannelPipeline的下一个ChannelHandler,在实现过程中只需要专注重写自己想要的方法即可,但是它不会自动的释放与池化ByteBuf相关的内存,需要手动调用 ReferenceCountUtil.release()自动的实现在SimpleChannelInboundHandler,注意如果要传递给下一个ChannelHandler需要调用 ReferenceCountUtil.retain()
  • ChannelOutboundHandler处理出站数据并且允许拦截所有的操作。ChannelOutboundHandlerAdapter对接口做了适配,默认调用ChannelHandlerContext相同的方法,实现转发到ChannelPipeline中的先一个ChannelHandler


Channel的各状态详解


当channel状态发生变化会转换成对应的事件交给ChannelHandler处理

ChannelHandler的声明周期详解

  1. handlerAdded:添加到ChannelPipeline时调用
  2. handlerRemoved:从ChannelPipeline中移除时调用
  3. exceptionCaught:处理过程中在ChannelPipeline中有错误产生时调用。对于入站异常来讲,从错误发生的那一点开始继续沿着入站方向流动,所以一般在最后一个ChannelInboundHandler实现。【出站异常一般通过返回的ChannelFuture注册listenner,通过 channelFuture.isSuccess 来判断是否出现异常,另一种方式是将ChannelFutureListener作为参数给写方法的ChannelPromise,他适合相对简单的异常处理】

ChannelHandler在ChannelPipeline中的布局是怎样的?


每个新建的channel都会被分配一个新的channelpipeline,而且在channel的整个生命周期中,这永远不会被改变

ChannelPipeline是怎么操作ChannelHandler?

  • addFirst(addLast):将channelhandler作为第一个(最后一个)处理器
  • addBefore(addAfter):在已经存在的channelhandler之前(之后)添加一个处理器
  • remove:从channelpipeline中删除一个已经存在的channelhandler
  • replace:将原channelpipeline中的channelhandler替换成新的
  • fire开头的方法:一般是调用channelpipeline中的下一个channelinboundchannelhandler对应的方法
  • 出站对应的write(read)则是写(读)channelpipeline的下一个channeloutboundhandler写(读)方法【其它出站方法类似】

ChannelHandlerContext与ChannelPipeline、ChannelHandler是什么关系?


ChannelHandlerContext用于管理它所关联的ChannelHandler和同一个ChannelPipeline中的下一个ChannelHandler的交互【每当有handler添加到pipleline时,都会创建context,创建之后context和handler的关系永远都不会变,因而可以缓存context的引用】,如果事件从channel或者channelpipeline上触发将沿整个pipeline传播,但是context上的相同触发方式只会传递给pipeline上的下一个能够处理的handler

ChannelHandler是否可以在多个ChannelPipeline中复用?

在实现的handler上方使用注解@Sharable【注意ChannelHandler本身处理逻辑的线程安全性】,这样多个pipeline就可以共享一个handler,这种方式可以用来收集跨多个channel的统计信息