Netty4
Netty是一個和MINA類似的Java NIO框架,目前的最新版本是4.0.13,這兩個框架的主要作者好像都是同一個韓國人。
Channel
Channel是Netty最核心的接口,一個Channel就是一個聯絡Socket的通道,通過Channel,你可以對Socket進行各種操作。
ChannelHandler
用Netty編寫網絡程序的時候,你很少直接操縱Channel,而是通過ChannelHandler來間接操縱Channel。
Netty中的所有handler都實現自ChannelHandler接口。按照輸出輸出來分,分為ChannelInboundHandler、ChannelOutboundHandler兩大類。
ChannelInboundHandler對從客戶端發往服務器的報文進行處理,一般用來執行解碼、讀取客戶端數據、進行業務處理等;
ChannelOutboundHandler對從服務器發往客戶端的報文進行處理,一般用來進行編碼、發送報文到客戶端。
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);
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的種類
Netty中的所有handler都實現自ChannelHandler接口。按照輸出輸出來分,分為ChannelInboundHandler、ChannelOutboundHandler兩大類。ChannelInboundHandler對從客戶端發往服務器的報文進行處理,一般用來執行解碼、讀取客戶端數據、進行業務處理等;ChannelOutboundHandler對從服務器發往客戶端的報文進行處理,一般用來進行編碼、發送報文到客戶端。
從上面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()方法:
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共同協作完成的。