Netty是基于Reactor模式的高性能网络框架,其主要是基于bossgroup和workergroup实现了主从Reactor模式,其中handler的调用链让用户自己定义对应的I/O处理逻辑,而这其中pipline是很重要的一环。在Netty Server端,每个Channel都会在初始化的时候都会实例化一个DefaultChannelPipeline
与之进行绑定,这个pipline中保存着handler的处理链。
在AbstractChannel
(NioServerSocketChannel和NioSocketChannel都是它的子类)进行初始化的时候,会将一个pipline初始化,并与自身绑定。
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}
当我们在服务端启动的时候增加handler的时候:
.childHandler(new ChannelInitializer<SocketChannel>()
{
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception
{
socketChannel.pipeline().addLast("hello world hanlder",new HelloWorldHandler());
}
}
,实际上是将handler加入到了NioSocketChannel的pipline的hanler链表上。(NioServerSocketChannel可以通过handler方法添加)
public final ChannelPipeline addLast(String name, ChannelHandler handler) {
return addLast(null, name, handler);
}
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
newCtx = newContext(group, filterName(name, handler), handler);// 返回 DefaultChannelHandlerContext
addLast0(newCtx);
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
这里引申出另外一个点就是,在DefaultPipline中,默认有两个Handler节点,分别是head
和 tail
两个节点。
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
这两个节点在整个handler调用链上有很大的作用,实际上上述代码可以发现,最终加入到pipline上的是通过封装后的DefaultChannelHandlerContext
也就是我们经常说的上下文。DefaultChannelHandlerContext
中包含有pipline
和handler
的引用,而pipline
中含有channel
和context
应用,形成了相互引用。
DefaultChannelHandlerContext
实际上是对Handler进行了一个封装。
在其父类AbstractChannelHandlerContext
,只有两个AbstractChannelHandlerContext
引用:
volatile AbstractChannelHandlerContext next;
volatile AbstractChannelHandlerContext prev;
在DefaultChannelPipeline
中的HeadContext
和TailContext
也是他的子类,我们常说的Netty中的handler链式处理实际上是通过AbstractChannelHandlerContext来实现了链式处理,并不是handler自己
一般我们在一个handler处理完之后,都建议调用ChannelHandlerContext.fireXXX
将这个调用链路继续往后传递下去。我们以read为例说明,当读取完数据后会触发pipeline.fireChannelRead
:
public final ChannelPipeline fireChannelRead(Object msg) {
AbstractChannelHandlerContext.invokeChannelRead(head, msg);
return this;
}
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRead(m);
} else {
executor.execute(new Runnable() {
public void run() {
next.invokeChannelRead(m);
}
});
}
}
private void invokeChannelRead(Object msg) {
if (invokeHandler()) {
try {
((ChannelInboundHandler) handler()).channelRead(this, msg);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRead(msg);
}
}
这里首先传入的是HeadContext
,可以看到,这里是会调用每个ChannelHandlerContext
的EventExecutor
去执行具体任务(也就是worker线程组里面的线程),然后执行invokeChannelRead
,这里首先会判断当前``ChannelHandlerContext是否加入到Handler执行链中,如果是,则执行对应Handler的channelRead
,这里的handler()
方法就是获取到ChannelHandlerContext中我们传入的Handler,这里开始传入的HeadContext:
// HeadContext
public ChannelHandler handler() {
return this;
}
HeadContext
中的handler()
方法获取到就是他自己,也就是这里会执行HeadContext.channelRead
:
ctx.fireChannelRead(msg);
没有任何处理,直接调用了ChannelHandlerContext.fireChannelRead
,在AbstractChannelHandlerContext
中实现如下:
public ChannelHandlerContext fireChannelRead(final Object msg) {
invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg);
return this;
}
这里invokeChannelRead
和上面的一样,但是findContextInbound
就是找到下一个待执行的hanler:
private AbstractChannelHandlerContext findContextInbound(int mask) {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while ((ctx.executionMask & mask) == 0);
return ctx;
}
这里会根据刚才上面说的ChannelHandlerContext
的链上每个ChannelHandlerContext 的executionMask 是否是给出的mask类型,那么这个怎么生成的呢,逻辑如下:
private static int mask0(Class<? extends ChannelHandler> handlerType) {
int mask = MASK_EXCEPTION_CAUGHT;
try {
if (ChannelInboundHandler.class.isAssignableFrom(handlerType)) {
mask |= MASK_ALL_INBOUND;
if (isSkippable(handlerType, "channelRegistered", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_REGISTERED;
}
if (isSkippable(handlerType, "channelUnregistered", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_UNREGISTERED;
}
if (isSkippable(handlerType, "channelActive", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_ACTIVE;
}
if (isSkippable(handlerType, "channelInactive", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_INACTIVE;
}
if (isSkippable(handlerType, "channelRead", ChannelHandlerContext.class, Object.class)) {
mask &= ~MASK_CHANNEL_READ;
}
if (isSkippable(handlerType, "channelReadComplete", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_READ_COMPLETE;
}
if (isSkippable(handlerType, "channelWritabilityChanged", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_WRITABILITY_CHANGED;
}
if (isSkippable(handlerType, "userEventTriggered", ChannelHandlerContext.class, Object.class)) {
mask &= ~MASK_USER_EVENT_TRIGGERED;
}
}
if (ChannelOutboundHandler.class.isAssignableFrom(handlerType)) {
mask |= MASK_ALL_OUTBOUND;
if (isSkippable(handlerType, "bind", ChannelHandlerContext.class,
SocketAddress.class, ChannelPromise.class)) {
mask &= ~MASK_BIND;
}
if (isSkippable(handlerType, "connect", ChannelHandlerContext.class, SocketAddress.class,
SocketAddress.class, ChannelPromise.class)) {
mask &= ~MASK_CONNECT;
}
if (isSkippable(handlerType, "disconnect", ChannelHandlerContext.class, ChannelPromise.class)) {
mask &= ~MASK_DISCONNECT;
}
if (isSkippable(handlerType, "close", ChannelHandlerContext.class, ChannelPromise.class)) {
mask &= ~MASK_CLOSE;
}
if (isSkippable(handlerType, "deregister", ChannelHandlerContext.class, ChannelPromise.class)) {
mask &= ~MASK_DEREGISTER;
}
if (isSkippable(handlerType, "read", ChannelHandlerContext.class)) {
mask &= ~MASK_READ;
}
if (isSkippable(handlerType, "write", ChannelHandlerContext.class,
Object.class, ChannelPromise.class)) {
mask &= ~MASK_WRITE;
}
if (isSkippable(handlerType, "flush", ChannelHandlerContext.class)) {
mask &= ~MASK_FLUSH;
}
}
if (isSkippable(handlerType, "exceptionCaught", ChannelHandlerContext.class, Throwable.class)) {
mask &= ~MASK_EXCEPTION_CAUGHT;
}
} catch (Exception e) {
PlatformDependent.throwException(e);
}
return mask;
}
其实就是判断当前ChannelHandlerContext 中的ChannelHandler是否有对应的方法
,这里channelRead
对应的就是MASK_CHANNEL_READ
,也就是说,在fireChannelRead
中会向后遍历ChannelHandlerContext ,如果有channelRead
方法,那么就会执行对应的方法.
如果在执行方法最后调用了ChannelHandlerContext .fireChannelRead
则会将这个调用链一直传递下去。
下面我们先以NioServerSocketChannel建立连接时pipline调用的逻辑处理为例来进行研究。当连接事件通知到来时会调用NioServerSocketChannel对应的pipline的 pipeline.fireChannelRead来进行相关处理。代码调用链如下:
//DefaultPipline中执行
public final ChannelPipeline fireChannelRead(Object msg) {
AbstractChannelHandlerContext.invokeChannelRead(head, msg);
return this;
}
//会调用 HeadHandler
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.fireChannelRead(msg);
}
ctx.fireChannelRead(msg);
实际上就是把事件往后续handler传递关键,如果自定义的实现里面没有显示的调用ctx.fireChannelRead(msg);
则handler事件传播会到当前结束(一些coder会在其父类中显示的调用,以便事件得以继续传播)