感谢博主。本文仅供参考学习。

目录(?)[-]

  1. Netty4
  2. Channel
  3. ChannelHandler
  4. ChannelPipeline
  5. ChannelHandlerContext
  6. ChannelPipeline和ChannelHandlerContext默认实现
  7. ChannelHandler的种类
  8. 事件的传播
  9. 参考资料

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。

netty channel存入redis netty的channel_java

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


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

根据上面的方法,能够大概想象的到Pipeline按照什么样的方式组织Handler。

ChannelHandlerContext

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

netty channel存入redis netty的channel_ide_02

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


ChannelPipeline和ChannelHandlerContext默认实现

DefaultChannelHandlerContext和DefaultChannelPipeline是ChannelHandlerContext和ChannelPipeline的默认实现,下面是它们的部分代码:


1. final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {  
2.   
3. volatile DefaultChannelHandlerContext next;  
4. volatile DefaultChannelHandlerContext prev;  
5.   
6. private final boolean inbound;  
7. private final boolean outbound;  
8. private final AbstractChannel channel;  
9. private final DefaultChannelPipeline pipeline;  
10. private final String name;  
11. private final ChannelHandler handler;  
12. private boolean removed;  
13.   
14. // ...  
15. }


1. final class DefaultChannelPipeline implements ChannelPipeline {  
2. // ...  
3.   
4. final DefaultChannelHandlerContext head;  
5. final DefaultChannelHandlerContext tail;  
6.   
7. // ...  
8. }

从上面的代码可以看出,在DefaultPipeline内部,DefaultChannelHandlerContext组成了一个双向链表:

netty channel存入redis netty的channel_ide_03

再来看看DefaultChannelPipeline的构造函数:


1. public DefaultChannelPipeline(AbstractChannel channel) {  
2. if (channel == null) {  
3. throw new NullPointerException("channel");  
4.     }  
5. this.channel = channel;  
6.   
7. new TailHandler();  
8. new DefaultChannelHandlerContext(this, null, generateName(tailHandler), tailHandler);  
9.   
10. new HeadHandler(channel.unsafe());  
11. new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler);  
12.   
13.     head.next = tail;  
14.     tail.prev = head;  
15. }

可以看到,DefaultChinnelPipeline内部使用了两个特殊的Handler来表示Handler链的头和尾:

netty channel存入redis netty的channel_java_04

ChannelHandler的种类

从上面DefaultChannelHandlerContext代码可以知道,Handler实际上分为两种,Inbound和Outbound,这一点也可以从ChannelHandler接口的子接口得到证明:



1. public interface ChannelInboundHandler extends ChannelHandler {  
2. // ...  
3. }  
4.   
5. public interface ChannelOutboundHandler extends ChannelHandler {  
6. // ...  
7. }

 

事件的传播

为了搞清楚事件如何在Pipeline里传播,让我们从Channel的抽象子类AbstractChannel开始,下面是AbstractChannel#write()方法的实现:



1. public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {  
2. // ...  
3. @Override  
4. public Channel write(Object msg) {  
5. return pipeline.write(msg);  
6.     }  
7. // ...  
8. }

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

netty channel存入redis netty的channel_构造函数_05

再看DefaultChannelPipeline的write()方法实现:



1. final class DefaultChannelPipeline implements ChannelPipeline {  
2. // ...  
3. @Override  
4. public ChannelFuture write(Object msg) {  
5. return tail.write(msg);  
6.     }  
7. // ...  
8. }

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

netty channel存入redis netty的channel_java_06

接着看DefaultChannelHandlerContext的write()方法:



1. final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {  
2. // ...  
3. @Override  
4. public ChannelFuture write(Object msg) {  
5. return write(msg, newPromise());  
6.     }  
7.   
8. @Override  
9. public ChannelFuture write(final Object msg, final ChannelPromise promise) {  
10. if (msg == null) {  
11. throw new NullPointerException("msg");  
12.         }  
13.   
14. true);  
15.   
16. false, promise);  
17.   
18. return promise;  
19.     }  
20.   
21. private void write(Object msg, boolean flush, ChannelPromise promise) {  
22.         DefaultChannelHandlerContext next = findContextOutbound();  
23.         next.invokeWrite(msg, promise);  
24. if (flush) {  
25.             next.invokeFlush();  
26.         }  
27.     }  
28.   
29. private DefaultChannelHandlerContext findContextOutbound() {  
30. this;  
31. do {  
32.             ctx = ctx.prev;  
33. while (!ctx.outbound);  
34. return ctx;  
35.     }  
36.   
37. private void invokeWrite(Object msg, ChannelPromise promise) {  
38. try {  
39. this, msg, promise);  
40. catch (Throwable t) {  
41.             notifyOutboundHandlerException(t, promise);  
42.         }  
43.     }  
44.   
45. // ...  
46. }

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

netty channel存入redis netty的channel_ide_07

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

netty channel存入redis netty的channel_java_08

最后看看ChannelOutboundHandlerAdapter的write()方法实现:

    
    1. public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {  
    2. // ...  
    3. @Override  
    4. public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {  
    5.         ctx.write(msg, promise);  
    6.     }  
    7. // ...  
    8. }

    默认的实现调用了context的write()方法而不做任何处理,这样write事件就沿着outbound链继续传播:

    netty channel存入redis netty的channel_ide_09

    可见,Pipeline的事件传播,是靠Pipeline,Context和Handler共同协作完成的。