Netty4 ChannelHandler 概述(通道篇)
点击上方“中间件兴趣圈”,选择“设为星标”
基于 Netty4 以源码分析为主要手段辅以流程图,从通道篇、内存篇、性能篇三个维度深度剖析Netty的实现原理。
本节主要介绍 Netty ChannelHandler 事件概述,并详细介绍各个事件方法的触发时机,为下篇关于事件传播机制打下坚实基础。
NIO 相关的核心类图如下:
ChannelHandler Netty Channel 事件的基础接口,只定义与 Handler 的管理接口相关,具体如下:
void handlerAdded(ChannelHandlerContext ctx)
在调用 DefaultChannelPipeline 的 addLast(add*) 将事件监听器添加到事件处理链条时调用。void handlerRemoved(ChannelHandlerContext ctx)
在调用DefaultChannelPipeline 的 addLast(add*) 发生异常时被调用;当通道关闭后,通道取消注册后,同时会触发通道移除事件,具体调用入口:DefaultChannelPipeline 的内部类 HeadContext 的 channelUnregistered。ChannelInboundHandler入端类型的事件处理器。
void channelRegistered(ChannelHandlerContext ctx)
通道注册到 Selector 时触发。客户端在调用 connect 方法,通过 TCP 建立连接后,获取 SocketChannel 后将该通道注册在 Selector 时或服务端在调用bind 方法后创建 ServerSocketChannel,通过将通道注册到 Selector 时监听客户端连接上时被调用。void channelUnregistered(ChannelHandlerContext ctx)
通道取消注册到Selector时被调用,通常在通道关闭时触发,首先触发channelInactive 事件,然后再触发 channelUnregistered 事件。void channelActive(ChannelHandlerContext ctx)
通道处于激活的事件,在 Netty 中,处于激活状态表示底层 Socket 的isOpen() 方法与 isConnected() 方法返回 true。void channelInactive(ChannelHandlerContext ctx)
通道处于非激活(关闭),调用了 close 方法时,会触发该事件,然后触发channelUnregistered 事件。void channelRead(ChannelHandlerContext ctx, Object msg)
通道从对端读取数据,当事件轮询到读事件,调用底层 SocketChanne 的 read 方法后,将读取的字节通过事件链进行处理,NIO 的触发入口为AbstractNioByteChannel 的内部类 NioByteUnsafe 的 read 方法。void channelReadComplete(ChannelHandlerContext ctx)
处理完一次通道读事件后触发,在 Netty 中一次读事件处理中,会多次调用SocketChannel 的 read方法。触发入口为AbstractNioByteChannel 的内部类NioByteUnsafe 的 read 方法。void userEventTriggered(ChannelHandlerContext ctx, Object evt)
触发用户自定义的事件,目前只定义了ChannelInputShutdownEvent(如果允许半关闭(输入端关闭而服务端不关闭))事件。void channelWritabilityChanged(ChannelHandlerContext ctx)
Netty 写缓存区可写状态变更事件(可写--》不可写、不可写--》可写),入口消息发送缓存区ChannelOutboundBuffer。void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
异常事件。ChannelOutboundHandler出端类型的事件处理器。
void bind(ChannelHandlerContext ctx, SocketAddress add, ChannelPromise p)
调用ServerBootstrap 的 bind 方法的处理逻辑。绑定操作,服务端在启动时调用bind方法时触发(手动调用bind)。void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,SocketAddress localAddress, ChannelPromise promise)
连接操作,客户端启动时调用connect方法时触发(手动调用connect)。void disconnect(ChannelHandlerContext ctx, ChannelPromise promise)
断开连接操作(手动调用disconnect)void close(ChannelHandlerContext ctx, ChannelPromise promise)
关闭通道,手动调用Channel#close方法时触发。(手动调用close)void deregister(ChannelHandlerContext ctx, ChannelPromise promise)
调用Channel#deregister时触发。(手动调用deregister)。void read(ChannelHandlerContext ctx) throws Exception
注册读事件,并不是触发网络读写事件。void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception
调用调用 Channel 的 write(底层 SocketChannel 的 write)时触发。void flush(ChannelHandlerContext ctx)
调用调用Channel#flush(SocketChannel#flush)时触发。ChannelDuplexHandler
双向 Handler,包含 Inbound 和 outbound 事件。ByteToMessageDecoder
解码器:字节流解码成一条一条的消息(Message、协议对象)。MessageToByteEncoder
编码器:消息(协议对象)编码成二进制字节流。AbstractTrafficShapingHandler
流量整形,将在后续章节中详细介绍。
上述详细的介绍了NettyChannel的类继承体系,并重点介绍了ChannelInboundHandler 与 ChannelOutboundHandler 每个方法的含义已经触发时机,接下来再谈一点我对这两个 Handler 的一些理解。
ChannelInboundHandler:入端操作,可以看出基本上是都是由事件选择器(NIO Selector事件就绪选择)进行触发,事件名称以 channel 开头,例如channelRead。
ChannelOutboundHanlder:出端操作,其触发点除了 read 事件外都是通过调用api(例如bind、connect、close、write)。
本文就介绍到这里了,主要目的是让大家对 Netty ChannelHandler 有一个基本的认识,为后续文章打下坚实的基础。
最后以一个思考题结束本文的讲解:ChannelInboundHandler 的channelRead 事件与 ChannelOutboundHandler 的 read 事件有什么区别呢?
温馨提示:如果需要与笔者关于上述问题进行交流,可以加笔者微信:dingwpmz。
欢迎加入我的知识星球,一起交流源码,探讨架构,揭秘亿级订单的架构设计与实践经验,打造高质量的技术交流圈,为广大星友提供高质量问答服务,长按如下二维码加入。
年度精彩热文TOP3