1. 程式人生 > >netty之pipeline

netty之pipeline

null nsa false apt contex head ide channel ati

轉載自https://blog.csdn.net/zxhoo/article/details/17264263

Netty4學習筆記(1)-- ChannelPipeline

Netty4
Netty是一個和MINA類似的Java NIO框架,目前的最新版本是4.0.13,這兩個框架的主要作者好像都是同一個韓國人。

Channel
Channel是Netty最核心的接口,一個Channel就是一個聯絡Socket的通道,通過Channel,你可以對Socket進行各種操作。

ChannelHandler
用Netty編寫網絡程序的時候,你很少直接操縱Channel,而是通過ChannelHandler來間接操縱Channel。

ChannelPipeline
ChannelPipeline實際上應該叫做ChannelHandlerPipeline,可以把ChannelPipeline看成是一個ChandlerHandler的鏈表,當需要對Channel進行某種處理的時候,Pipeline負責依次調用每一個Handler進行處理。每個Channel都有一個屬於自己的Pipeline,調用Channel#pipeline()方法可以獲得Channel的Pipeline,調用Pipeline#channel()方法可以獲得Pipeline的Channel。

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

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按照什麽樣的方式組織Handler。

ChannelHandlerContext
ChannelPipeline並不是直接管理ChannelHandler,而是通過ChannelHandlerContext來間接管理,這一點通過ChannelPipeline的默認實現DefaultChannelPipeline可以看出來。

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

ChannelPipeline和ChannelHandlerContext默認實現

DefaultChannelHandlerContext和DefaultChannelPipeline是ChannelHandlerContext和ChannelPipeline的默認實現,下面是它們的部分代碼:

final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {

volatile DefaultChannelHandlerContext next;
volatile DefaultChannelHandlerContext prev;

private final boolean inbound;
private final boolean outbound;
private final AbstractChannel channel;
private final DefaultChannelPipeline pipeline;
private final String name;
private final ChannelHandler handler;
private boolean removed;

// ...
}
final class DefaultChannelPipeline implements ChannelPipeline {
// ...

final DefaultChannelHandlerContext head;
final DefaultChannelHandlerContext tail;

// ...
}

從上面的代碼可以看出,在DefaultPipeline內部,DefaultChannelHandlerContext組成了一個雙向鏈表:


再來看看DefaultChannelPipeline的構造函數:

public DefaultChannelPipeline(AbstractChannel channel) {
if (channel == null) {
throw new NullPointerException("channel");
}
this.channel = channel;

TailHandler tailHandler = new TailHandler();
tail = new DefaultChannelHandlerContext(this, null, generateName(tailHandler), tailHandler);

HeadHandler headHandler = new HeadHandler(channel.unsafe());
head = new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler);

head.next = tail;
tail.prev = head;
}

可以看到,DefaultChinnelPipeline內部使用了兩個特殊的Handler來表示Handler鏈的頭和尾:


ChannelHandler的種類
從上面DefaultChannelHandlerContext代碼可以知道,Handler實際上分為兩種,Inbound和Outbound,這一點也可以從ChannelHandler接口的子接口得到證明:

public interface ChannelInboundHandler extends ChannelHandler {
// ...
}

public interface ChannelOutboundHandler extends ChannelHandler {
// ...
}

事件的傳播
為了搞清楚事件如何在Pipeline裏傳播,讓我們從Channel的抽象子類AbstractChannel開始,下面是AbstractChannel#write()方法的實現:

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
// ...
@Override
public Channel write(Object msg) {
return pipeline.write(msg);
}
// ...
}

AbstractChannel直接調用了Pipeline的write()方法:


再看DefaultChannelPipeline的write()方法實現:

final class DefaultChannelPipeline implements ChannelPipeline {
// ...
@Override
public ChannelFuture write(Object msg) {
return tail.write(msg);
}
// ...
}

因為write是個outbound事件,所以DefaultChannelPipeline直接找到tail部分的context,調用其write()方法:


接著看DefaultChannelHandlerContext的write()方法:

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()方法:

最後看看ChannelOutboundHandlerAdapter的write()方法實現:

public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {
// ...
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
ctx.write(msg, promise);
}
// ...
}

默認的實現調用了context的write()方法而不做任何處理,這樣write事件就沿著outbound鏈繼續傳播:


可見,Pipeline的事件傳播,是靠Pipeline,Context和Handler共同協作完成的。


---------------------
作者:zxh0
來源:CSDN
原文:https://blog.csdn.net/zxhoo/article/details/17264263
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

netty之pipeline