读写事件流程分析与相关API

Catalogue
  1. Channel
  2. ChannelHandler
    1. ChannelHandler的种类:
  3. ChannelPipeline
    1. 事件的传播
  4. ChannelHandlerContext

netty5笔记-总体流程分析3-ChannelHandlerContext

Netty4学习笔记(1)— ChannelPipeline

处理链处理写操作流程、Pipeline,Context和Handler的协作处理。

netty核心的概念:Channel、Buffer、Selecter

Channel

Channel是核心的一个接口,表示一个联络Socket的通道。通过Channel,可以对Socket进行各种操作。

ChannelHandler

在实际程序实现中,很少直接操作Channel,而是通过ChannelHandler来间接操纵Channel。(使用策略模式?)

ChannelHandler的种类:

ChannelHandler接口的子接口

  • ChannelInboundHandler
  • ChannelOutboundHandler

5.0.0.Alpha1 版本已经没有了这两个接口,why。4.1.5存在。

ChannelPipeline

ChannelPipeline里有一个双向链表,使用HashMap存放节点。节点类型为:ChannelHandlerContext。

是一个ChandlerHandler的链表。当需要对Channel进行某种处理的时候,Pipeline负责依次调用每一个Handler进行处理。(责任链模式?)

每个Channel都有一个属于自己的Pipeline.(一对一关系)

ChannelPipeline的方法有很多,其中一部分是用来管理ChannelHandler的,如下面这些:

1
2
3
4
5
6
7
8
9
10
11
12
13
ChannelPipeline addFirst(String name, ChannelHandler handler);  
ChannelPipeline addLast(String name, ChannelHandler handler);
ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);
ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);
ChannelPipeline remove(ChannelHandler handler);
ChannelHandler remove(String name);
ChannelHandler removeFirst();
ChannelHandler removeLast();
ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);
ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);
ChannelHandler first();
ChannelHandler last();
ChannelHandler get(String name);

事件的传播

为了搞清楚事件如何在Pipeline里传播,

  • 让我们从Channel的抽象子类AbstractChannel开始:
1
2
3
4
5
6
7
8
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {  
// ...
@Override
public Channel write(Object msg) {
return pipeline.write(msg);
}
// ...
}
  • 再看DefaultChannelPipeline的write()方法实现
1
2
3
4
5
6
7
8
final class DefaultChannelPipeline implements ChannelPipeline {  
// ...
@Override
public ChannelFuture write(Object msg) {
return tail.write(msg);
}
// ...
}

因为write是个outbound事件,所以DefaultChannelPipeline直接找到tail部分的context,调用其write()方法

  • 接着看DefaultChannelHandlerContext的write()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {  
// ...
@Override
public ChannelFuture write(Object msg) {
return write(msg, newPromise());
}

@Override
public ChannelFuture write(final Object msg, final ChannelPromise promise) {
if (msg == null) {
throw new NullPointerException("msg");
}

validatePromise(promise, true);

write(msg, false, promise);

return promise;
}

private void write(Object msg, boolean flush, ChannelPromise promise) {
DefaultChannelHandlerContext next = findContextOutbound();
next.invokeWrite(msg, promise);
if (flush) {
next.invokeFlush();
}
}

private DefaultChannelHandlerContext findContextOutbound() {
DefaultChannelHandlerContext ctx = this;
do {
ctx = ctx.prev;
} while (!ctx.outbound);
return ctx;
}

private void invokeWrite(Object msg, ChannelPromise promise) {
try {
((ChannelOutboundHandler) handler).write(this, msg, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
}

// ...
}

context的write()方法沿着context链往前找,直至找到一个outbound类型的context为止,然后调用其invokeWrite()方法

invokeWrite()接着调用handler的write()方法:

ChannelHandlerContext

ChannelPipeline并不是直接管理ChannelHandler,而是通过ChannelHandlerContext来间接管理,这一点通过ChannelPipeline的默认实现DefaultChannelPipeline可以看出来。

调用ChannelHandlerContext#channel()方法可以得到和Context绑定的Channel,调用ChannelHandlerContext#handler()方法可以得到和Context绑定的Handler。

一个ChannelHandlerContext只能对应一个ChannelHander,只对应一个Channel,而一个ChannelHander则可以对应多个ChannelHandlerContext