netty源码分析之ChannelPipeline

看了ChannelHandler我们就来看ChannelPipeline,这个类实现了责任链模式,我们就直接来看这个类的实现吧,看完后我们再看看javadoc的,这个写的很详细。

       

Java代码   收藏代码
  1. static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelPipeline.class);  
  2.    static final ChannelSink discardingSink = new DiscardingChannelSink();  
  3.   
  4.    private volatile Channel channel;  
  5.    private volatile ChannelSink sink;  
  6.    private volatile DefaultChannelHandlerContext head;  
  7.    private volatile DefaultChannelHandlerContext tail;  
  8.    private final Map<String, DefaultChannelHandlerContext> name2ctx =  
  9.        new HashMap<String, DefaultChannelHandlerContext>(4);  

       这个里面的很好理解,channel就是和这个pipeline相关联的,sink也是和这个chanel相关联的对象,在pipeline里面会调度channelhandler的运行,在运行之后交给sink去处理传输等比较底层的操作。head和tail和name2ctx是这个pipe里面的一个ChanelHandlerContext的一个链式结构。

 

Java代码   收藏代码
  1. public ChannelSink getSink() {  
  2.        ChannelSink sink = this.sink;  
  3.        if (sink == null) {  
  4.            return discardingSink;  
  5.        }  
  6.        return sink;  
  7.    }  

        在这个里面可以看到单不传递sink的时候,默认使用discardingSink。

 

Java代码   收藏代码
  1. public void attach(Channel channel, ChannelSink sink) {  
  2.         if (channel == null) {  
  3.             throw new NullPointerException("channel");  
  4.         }  
  5.         if (sink == null) {  
  6.             throw new NullPointerException("sink");  
  7.         }  
  8.         if (this.channel != null || this.sink != null) {  
  9.             throw new IllegalStateException("attached already");  
  10.         }  
  11.         this.channel = channel;  
  12.         this.sink = sink;  
  13.     }  

          这个里面实现channel和sink与这个pipeline的绑定,可以看出来,一个pipe会和一个channel和sink相绑定。

         下来来看一下链表channelhandler的操作:

          

Java代码   收藏代码
  1. public synchronized void addFirst(String name, ChannelHandler handler) {  
  2.         if (name2ctx.isEmpty()) {  
  3.             init(name, handler);  
  4.         } else {  
  5.             checkDuplicateName(name);  
  6.             DefaultChannelHandlerContext oldHead = head;  
  7.             DefaultChannelHandlerContext newHead = new DefaultChannelHandlerContext(null, oldHead, name, handler);  
  8.   
  9.             callBeforeAdd(newHead);  
  10.   
  11.             oldHead.prev = newHead;  
  12.             head = newHead;  
  13.             name2ctx.put(name, newHead);  
  14.   
  15.             callAfterAdd(newHead);  
  16.         }  
  17.     }  

        如果链表是空的时候实现初始化的一些操作,初始化head、tail变量,然后如果这个handler是实现LifeCycleChannelHandler的,就触发相应的动作。如果不是初始化的时候,就修改一下head指针,这个是比较好理解的。

        同理addLast要修改相应的tail指针,addBefore修改prev,addAfter修改next指针,这些都比较好理解,就不多解释了。需要注意的是这些方法都是一些同步方法,都加了synchronized关键字,不知道这个地方是否可以使用ConcurrentHashMap。

       中间的一些链表操作我们就不多讲了,但是写的感觉比较好,都比较精彩,作者的功底很高,我们接下来看一下调度:

 

Java代码   收藏代码
  1. public void sendUpstream(ChannelEvent e) {  
  2.        DefaultChannelHandlerContext head = getActualUpstreamContext(this.head);  
  3.        if (head == null) {  
  4.            logger.warn(  
  5.                    "The pipeline contains no upstream handlers; discarding: " + e);  
  6.            return;  
  7.        }  
  8.   
  9.        sendUpstream(head, e);  
  10.    }  
  11.   
  12.    void sendUpstream(DefaultChannelHandlerContext ctx, ChannelEvent e) {  
  13.        try {  
  14.            ((ChannelUpstreamHandler) ctx.getHandler()).handleUpstream(ctx, e);  
  15.        } catch (Throwable t) {  
  16.            notifyHandlerException(e, t);  
  17.        }  
  18.    }  

            sendUpstream可以看到是从head开始走,然后找到下一个可以处理upstream的handler进行处理,然后让HandlerContext找到当前的下一个到下一个,慢慢的处理upstream事件,最后让交给ChannelSink组件。

         

Java代码   收藏代码
  1. public void sendDownstream(ChannelEvent e) {  
  2.        DefaultChannelHandlerContext tail = getActualDownstreamContext(this.tail);  
  3.        if (tail == null) {  
  4.            try {  
  5.                getSink().eventSunk(this, e);  
  6.                return;  
  7.            } catch (Throwable t) {  
  8.                notifyHandlerException(e, t);  
  9.                return;  
  10.            }  
  11.        }  
  12.   
  13.        sendDownstream(tail, e);  
  14.    }  
  15.   
  16.    void sendDownstream(DefaultChannelHandlerContext ctx, ChannelEvent e) {  
  17.        if (e instanceof UpstreamMessageEvent) {  
  18.            throw new IllegalArgumentException("cannot send an upstream event to downstream");  
  19.        }  
  20.          
  21.        try {  
  22.            ((ChannelDownstreamHandler) ctx.getHandler()).handleDownstream(ctx, e);  
  23.        } catch (Throwable t) {  
  24.            // Unlike an upstream event, a downstream event usually has an  
  25.            // incomplete future which is supposed to be updated by ChannelSink.  
  26.            // However, if an exception is raised before the event reaches at  
  27.            // ChannelSink, the future is not going to be updated, so we update  
  28.            // here.  
  29.            e.getFuture().setFailure(t);  
  30.            notifyHandlerException(e, t);  
  31.        }  
  32.    }  

              sendDownstream我们可以看到是找到最后一个Handler,然后找到前一个可以处理downstream事件的handler进行处理。

           最后我们来看一下javadoc里面给的例子程序:

           

Java代码   收藏代码
  1. ChannelPipeline p = Channels.pipeline();  
  2.  p.addLast("1"new UpstreamHandlerA());  
  3.  p.addLast("2"new UpstreamHandlerB());  
  4.  p.addLast("3"new DownstreamHandlerA());  
  5.  p.addLast("4"new DownstreamHandlerB());  
  6.  p.addLast("5"new UpstreamHandlerX());  

         我们可以看到,upstream事件的执行顺序是从头部找到第一个可以处理upstream事件的handler开始执行,所以执行顺序应该是1 --> 2 --> 5.

         downstream事件的执行顺序是从尾部找到第一个可以处理downstream事件的handler开始执行,所以执行顺序是 4 --> 3.

          在javadoc里面给我们指出了handler很灵活可以在运行的过程中自动的增加和删除,但是同时指出了下面的实现是错误的:

          

Java代码   收藏代码
  1. public class FirstHandler extends SimpleChannelUpstreamHandler {  
  2.   
  3.     @Override  
  4.     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {  
  5.         // Remove this handler from the pipeline,  
  6.         ctx.getPipeline().remove(this);  
  7.         // And let SecondHandler handle the current event.  
  8.         ctx.getPipeline().addLast("2nd"new SecondHandler());  
  9.         ctx.sendUpstream(e);  
  10.     }  
  11. }  

       我们看出这个是错误的,remove方法会破坏这个链,所有应该在remove之前add,这个相信大家都不会犯这样的错误的。

分享到:

你可能感兴趣的:(netty源码分析之ChannelPipeline)