Netty 5.0
主题结构
Channel(I) - AbstractChannel- AbstractNioChannel- AbstractNioByteChannel - NioSocketChannel
1. 内部有一个 DefaultChannelPipeline, 定义的 connect, read, write等方法实际是调用pipeline的方法
private final DefaultChannelPipeline pipeline;
2. 内部有 远端地址和本地地址
3. 内部有 一个unsafe对象, 与Channel成伴出现, 例如 NioByteUnsafe与AbstractNioByteChannel成对出现
ChannelPipeline(I) - DefaultChannelPipeline
1. 内部是一个链表,链表由 ChannelHandlerContext 组成。
2. 声明处理流链表的build操作,如 add, remove等等, 参数可以是 handler的name, handler实例等
3. 声明对链表的整体功能操作,如 read, write, close, bind等等,并没有真实实现,其实还是交给链表中的每个节点(ctx)完成
ChannelHandlerContext(I) - AbstractChannelHandlerContext
1. 标记当前的Handler的属性和状态,比如是inbound还是outbound, 是否是invokedPrevRead(准备读)状态等
2. 提供了一个invoker来调用实际的方法,在inbound, outbound的方法被调用时, 比如调用read()的时候,找到outbound,遍历outbound,执行每个invoker的read()方法。其实是交给了invoker完成
ChannelHandlerInvoker(I) - DefaultChannelHandlerInvoker
1. 定义了一个EventExecutor(ScheduledExecutorService) , 负责实际任务的线程控制
2. 声明和实现了方法的线程控制部分,如果当前线程是executor线程,执行任务,否则创建子线程执行。
3. 执行一些前置的判定等等,实际工作还是交给handler执行
ChannelHandler(I) - ChannelHandlerAdapter
1. 处理流链表中的节点, 如 read(ChannelHandlerContext ctx)
2. 处理的I/O事件或截获的I/O操作,并将其转发给ChannelPipeline中的下一个处理节点
调用过程案例:
Channel.write -> ChannelPipeline.write -> ChannelHandlerContext.write -> ChannelHandlerInvoker.write -> ChannelHandler.write
niosocketChannel.read -> pipeline.read -> ctx.read -> invoker.read -> handler.read -> unsafe.read;
Inbound和outBound的区别
与数据的流向无关,而是触发的方式,由外部网络引起的为in, 由程序员定义的代码引起的为out,即可以理解为in为注册后被动的触发方法,out为程序主动调用之方法, in方法以fire开头,out方法也有read
重点类
SimpleChannelInboundHandler: extends ChannelHandlerAdapter
1. 多了一个abstract方法:messageReceived(ChannelHandlerContext ctx, I msg),在channelRead中被调用
2. 5.0版本目前没有SimpleChannelOutboundHandler, ChannelOutBoundHandler也被注掉了
重点javadoc
A list of ChannelHandlers which handles or intercepts inbound events and outbound operations of a Channel.
ChannelPipeline implements an advanced form of the Intercepting Filter pattern to give a user full control over how an
event is handled and how the ChannelHandlers in a pipeline interact with each other. Creation of a pipeline
Each channel has its own pipeline and it is created automatically when a new channel is created. How an event flows in a pipeline
The following diagram describes how I/O events are processed by ChannelHandlers in a ChannelPipeline typically. An I/O event is handled by a ChannelHandler and is forwarded by the ChannelHandler which handled the event to the
ChannelHandler which is placed right next to it. A ChannelHandler can also trigger an arbitrary I/O event if necessary. To
forward or trigger an event, a ChannelHandler calls the event propagation methods defined in ChannelHandlerContext,
such as ChannelHandlerContext.fireChannelRead(Object) and ChannelHandlerContext.write(Object).
An inbound event is handled by the ChannelHandlers in the bottom-up direction as shown on the left side of the
diagram. An inbound event is usually triggered by the I/O thread on the bottom of the diagram so that the
ChannelHandlers are notified when the state of a Channel changes (e.g. newly established connections and closed connections) or the inbound data was read from a remote peer. If an inbound event goes beyond the ChannelHandler at the top of the diagram, it is discarded and logged, depending on your loglevel.
An outbound event is handled by the ChannelHandlers in the top-down direction as shown on the right side of the
diagram. An outbound event is usually triggered by your code that requests an outbound I/O operation, such as a write request and a connection attempt. If an outbound event goes beyond the ChannelHandler at the bottom of the diagram, it is handled by an I/O thread associated with the Channel. The I/O thread often performs the actual output operation such as SocketChannel.write(ByteBuffer).
Forwarding an event to the next handler
As explained briefly above, a ChannelHandler has to invoke the event propagation methods in ChannelHandlerContext
to forward an event to its next handler. Those methods include:
- Inbound event propagation methods:
- ChannelHandlerContext.fireChannelRegistered()
- ChannelHandlerContext.fireChannelActive()
- ChannelHandlerContext.fireChannelRead(Object)
- ChannelHandlerContext.fireChannelReadComplete()
- ChannelHandlerContext.fireExceptionCaught(Throwable)
- ChannelHandlerContext.fireUserEventTriggered(Object)
- ChannelHandlerContext.fireChannelWritabilityChanged()
- ChannelHandlerContext.fireChannelInactive()
- Outbound event propagation methods:
- ChannelHandlerContext.bind(SocketAddress, ChannelPromise)
- ChannelHandlerContext.connect(SocketAddress, SocketAddress, ChannelPromise)
- ChannelHandlerContext.write(Object, ChannelPromise)
- ChannelHandlerContext.flush()
- ChannelHandlerContext.read()
- ChannelHandlerContext.disconnect(ChannelPromise)
- ChannelHandlerContext.close(ChannelPromise) and the following example shows how the event propagation is