- 类图
- 顶层接口:ChannelHandler
- ChannelInboundHandler接口 和 ChannelOutboundHandler接口 和 ChannelHandlerAdapter抽象类
- ChannelInboundHandlerAdapter接口 和 ChannelOutboundHandlerAdapter接口
- SimpleChannelInboundHandler
1. 接口ChannelHandler
方法:其中 ctx 为 ChannelHandlerContext 类 void handlerAdded( ctx ) 当把 ChannelHandler 添加到 ChannelPipeline 中时被调用 void handlerRemoved( ctx ) 当从 ChannelPipeline 中移除 ChannelHandler 时被调用 void exceptionCaught(ctx , Throwable var2) 当处理过程中在 ChannelPipeline 中有错误产生时被调用 public @interface Sharable {}
2.1 接口ChannelInboundHandler
方法:其中 ctx 为 ChannelHandlerContext 类 void channelRegistered( ctx ) 当 Channel 已经注册到它的 EventLoop 并且能够处理 I/O 时被调用 channelUnregistered( ctx ) 当 Channel 从它的 EventLoop 注销并且无法处理任何 I/O 时被调用 channelActive( ctx ) 当 Channel 处于活动状态时被调用;Channel 已经连接/绑定并且已经就绪 channelInactive( ctx ) 当 Channel 离开活动状态并且不再连接它的远程节点时被调用 channelReadComplete( ctx ) 当Channel上的一个读操作完成时被调用 channelRead( ctx, object ) 读取数据时被调用。注:实现类重写这个方法时需要在最后添加ReferenceCountUtil.release(msg);方法来释放ByteBuf相关内存。一个简单的方式是使用SimpleChannelInboundHandler,后者帮你实现好了,会自动释放资源 channelWritabilityChanged( ctx ) 当 Channel 的可写状态发生改变时被调用。用户可以确保写操作不会完成
得太快(以避免发生 OutOfMemoryError)或者可以在 Channel 变为再
次可写时恢复写入。可以通过调用 Channel 的 isWritable()方法来检测
Channel 的可写性。与可写性相关的阈值可以通过 Channel.config().
setWriteHighWaterMark()和 Channel.config().setWriteLowWaterMark()方法来设置userEventTriggered( ctx, object ) 当 ChannelnboundHandler.fireUserEventTriggered()方法被调用时被调用,因为一个 POJO 被传经了 ChannelPipeline 2.2 接口ChannelOutboundHandler
其中ChannelPromise是ChannelFuture的一个 子类 void bind(ctx, SocketAddress var2, ChannelPromise var3) 当请求将 Channel 绑定到本地地址时被调用 void connect(ctx, SocketAddress var2, SocketAddress var3, ChannelPromise var4) 当请求将 Channel 连接到远程节点时被调用 void disconnect(ctx, ChannelPromise var2) 当请求将 Channel 从远程节点断开时被调用 void close(ctx, ChannelPromise var2) 当请求关闭 Channel 时被调用 void deregister(ctx, ChannelPromise var2) 当请求将 Channel 从它的 EventLoop 注销 时被调用 void read(ctx) 当请求从 Channel 读取更多的数据时被调用 void write(ctx, Object var2, ChannelPromise var3) 当请求通过 Channel 将数据写到远程节点时被调用。需要注意的是实现类在重写该方法时需要勿忘两件事:1.加上ReferenceCountUtil.release(msg);方法来释放ByteBuf相关内存;2.加上promise.setSuccess()进行通知,否则ChannelFutureListener收不到某个消息已经被处理了的通知情况 void flush(ctx) 当请求通过 Channel 将入队数据冲刷到远程 节点时被调用
3. 抽象类ChannelHandlerAdapter
public boolean isSharable() 实现了两个与shareable注解相关方法:如果isSharable()对应的实现被标注为 Sharable,那么这个方法将返回 true,表示它可以被添加到多个 ChannelPipeline中 protected void ensureNotSharable() void handlerRemoved( ctx ) 继承根接口ChannelHandler,空方法 void handlerAdded( ctx ) 继承根接口ChannelHandler,空方法 public void exceptionCaught(ctx , Throwable cause) ctx.fireExceptionCaught(cause);
4.1 接口ChannelInboundHandlerAdapter
public void exceptionCaught( ctx, Throwable cause ) 继承自抽象父类ChannelHandlerAdapter ctx.fireExceptionCaught(cause) 总共八个方法,全部继承自父接口ChannelInboundHandler,委托给ctx实现,并加了@Skip注解,以channelRead( ctx,Obj msg )为例 ctx.fireChannelRead(msg) 4.2 接口ChannelOutboundHandlerAdapter
总共八个方法,全部继承自父接口ChannelOutboundHandler,委托给ctx实现,并加了@Skip注解。以bind(ctx, SocketAddress var2, ChannelPromise var3) 为例 ctx.bind(localAddress, promise)
5.1 SimpleChannelInboundHandler
1. 该实现类继承自ChannelInboundHandlerAdapter,与ChannelInboundHandlerAdapter的不同在于channelRead0() 和 channelRead()两个方法。实现这个类的时候只需重写channelRead0()方法
- channelRead():继承自父类,与父类的区别在于,提供了一个模板:帮你实现好了ReferenceCountUtil.release(msg);释放资源,实际内容由channelRead0()负责
@Override// 继承了 ChannelInboundHandlerAdapter#channelRead public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { boolean release = true; try { if (acceptInboundMessage(msg)) { @SuppressWarnings("unchecked") I imsg = (I) msg; channelRead0(ctx, imsg);// 模板方法,抽出可变的部分,具体实现在子类中 } else { release = false; ctx.fireChannelRead(msg); } } finally { if (autoRelease && release) { ReferenceCountUtil.release(msg);// 释放资源(保存消息的ByteBuf) } } }
channelRead0():抽象方法,真正需要重写的逻辑
protected abstract void channelRead0(ChannelHandlerContext var1, I var2) throws Exception;
2. 为什么要设计SimpleChannelInboundHandler这个类?
- 在客户端,当 channelRead0() 方法完成时,你已经有了传入消息,并且已经处理完它了。当该方法返回时,SimpleChannelInboundHandler负责释放指向保存该消息的ByteBuf的内存引用。
- 在服务端中,有时你仍然需要将传入消息回送给发送者,而 write() 操作是异步的,直到 channelRead() 方法返回后可能仍然没有完成。为此,EchoServerHandler扩展了 ChannelInboundHandlerAdapter ,其在这个时间点上不会释放消息。
- Reference:https://blog.csdn.net/u010739551/article/details/89496731