Netty4
Netty是一個和MINA相似的Java NIO框架,目前的最新版本是4.0.13,這兩個框架的主要做者好像都是同一個韓國人。html
Channel
Channel是Netty最核心的接口,一個Channel就是一個聯絡Socket的通道,經過Channel,你能夠對Socket進行各類操做。java
ChannelHandler
用Netty編寫網絡程序的時候,你不多直接操縱Channel,而是經過ChannelHandler來間接操縱Channel。apache
ChannelPipeline
ChannelPipeline實際上應該叫作ChannelHandlerPipeline,能夠把ChannelPipeline當作是一個ChandlerHandler的鏈表,當須要對Channel進行某種處理的時候,Pipeline負責依次調用每個Handler進行處理。每一個Channel都有一個屬於本身的Pipeline,調用Channel#pipeline()方法能夠得到Channel的Pipeline,調用Pipeline#channel()方法能夠得到Pipeline的Channel。api
ChannelPipeline的方法有不少,其中一部分是用來管理ChannelHandler的,以下面這些:promise
- 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。ide
ChannelPipeline和ChannelHandlerContext默認實現函數
DefaultChannelHandlerContext和DefaultChannelPipeline是ChannelHandlerContext和ChannelPipeline的默認實現,下面是它們的部分代碼:this
- 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共同協做完成的。
參考資料
netty.io
Netty in Action
Intercepting Filter