`

netty源码分析之ChannelPipeline

阅读更多

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

       

 static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelPipeline.class);
    static final ChannelSink discardingSink = new DiscardingChannelSink();

    private volatile Channel channel;
    private volatile ChannelSink sink;
    private volatile DefaultChannelHandlerContext head;
    private volatile DefaultChannelHandlerContext tail;
    private final Map<String, DefaultChannelHandlerContext> name2ctx =
        new HashMap<String, DefaultChannelHandlerContext>(4);

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

 

 public ChannelSink getSink() {
        ChannelSink sink = this.sink;
        if (sink == null) {
            return discardingSink;
        }
        return sink;
    }

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

 

public void attach(Channel channel, ChannelSink sink) {
        if (channel == null) {
            throw new NullPointerException("channel");
        }
        if (sink == null) {
            throw new NullPointerException("sink");
        }
        if (this.channel != null || this.sink != null) {
            throw new IllegalStateException("attached already");
        }
        this.channel = channel;
        this.sink = sink;
    }

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

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

          

public synchronized void addFirst(String name, ChannelHandler handler) {
        if (name2ctx.isEmpty()) {
            init(name, handler);
        } else {
            checkDuplicateName(name);
            DefaultChannelHandlerContext oldHead = head;
            DefaultChannelHandlerContext newHead = new DefaultChannelHandlerContext(null, oldHead, name, handler);

            callBeforeAdd(newHead);

            oldHead.prev = newHead;
            head = newHead;
            name2ctx.put(name, newHead);

            callAfterAdd(newHead);
        }
    }

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

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

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

 

 public void sendUpstream(ChannelEvent e) {
        DefaultChannelHandlerContext head = getActualUpstreamContext(this.head);
        if (head == null) {
            logger.warn(
                    "The pipeline contains no upstream handlers; discarding: " + e);
            return;
        }

        sendUpstream(head, e);
    }

    void sendUpstream(DefaultChannelHandlerContext ctx, ChannelEvent e) {
        try {
            ((ChannelUpstreamHandler) ctx.getHandler()).handleUpstream(ctx, e);
        } catch (Throwable t) {
            notifyHandlerException(e, t);
        }
    }

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

         

 public void sendDownstream(ChannelEvent e) {
        DefaultChannelHandlerContext tail = getActualDownstreamContext(this.tail);
        if (tail == null) {
            try {
                getSink().eventSunk(this, e);
                return;
            } catch (Throwable t) {
                notifyHandlerException(e, t);
                return;
            }
        }

        sendDownstream(tail, e);
    }

    void sendDownstream(DefaultChannelHandlerContext ctx, ChannelEvent e) {
        if (e instanceof UpstreamMessageEvent) {
            throw new IllegalArgumentException("cannot send an upstream event to downstream");
        }
        
        try {
            ((ChannelDownstreamHandler) ctx.getHandler()).handleDownstream(ctx, e);
        } catch (Throwable t) {
            // Unlike an upstream event, a downstream event usually has an
            // incomplete future which is supposed to be updated by ChannelSink.
            // However, if an exception is raised before the event reaches at
            // ChannelSink, the future is not going to be updated, so we update
            // here.
            e.getFuture().setFailure(t);
            notifyHandlerException(e, t);
        }
    }

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

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

           

ChannelPipeline p = Channels.pipeline();
 p.addLast("1", new UpstreamHandlerA());
 p.addLast("2", new UpstreamHandlerB());
 p.addLast("3", new DownstreamHandlerA());
 p.addLast("4", new DownstreamHandlerB());
 p.addLast("5", new UpstreamHandlerX());

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

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

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

          

 public class FirstHandler extends SimpleChannelUpstreamHandler {

     @Override
     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
         // Remove this handler from the pipeline,
         ctx.getPipeline().remove(this);
         // And let SecondHandler handle the current event.
         ctx.getPipeline().addLast("2nd", new SecondHandler());
         ctx.sendUpstream(e);
     }
 }

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

分享到:
评论

相关推荐

    netty源码深入分析

    《Netty源码深入分析》是由美团基础架构部的闪电侠老师所分享的一系列关于Netty源码解析的视频教程。以下将根据标题、描述、标签以及部分内容等信息,对Netty及其源码进行深入剖析。 ### Netty简介 Netty是基于...

    netty源码解析视频

    #### 五、Netty源码分析实战案例 1. **ChannelHandlerContext与ChannelHandlerAdaptor详解**: - 分析`ChannelHandlerContext`的生命周期及其与`ChannelHandler`之间的交互方式。 - 深入理解`...

    netty源码 4.*版本

    在深入探讨 Netty 源码之前,我们先了解一下 Netty 的核心概念和架构。 Netty 的主要特点包括: 1. **异步非阻塞I/O**:Netty 基于 NIO(Non-blocking I/O)库,利用了 Java 的 Channel 和 Selector,使得网络操作...

    netty源码解析视频.txt

    通过对Netty源码的深入分析,我们不仅能够了解到其内部工作原理,还能学习到许多优秀的设计思想和技术实践,这对于提高个人的技术水平和解决实际问题有着非常重要的意义。希望本文能够帮助读者更好地理解和掌握Netty...

    netty源码+Spring源码视频教程.txt

    ### Netty源码分析 #### 1. Netty简介 Netty是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器与客户端。其核心设计思想是简化网络编程的复杂性,并提供高度可定制化的API,...

    netty源码深入剖析.txt

    《Netty源码深入剖析》一书旨在帮助读者深入了解Netty框架的工作原理和技术细节,从基础知识入手,逐步过渡到高级优化技巧,使开发者能够更好地掌握并应用Netty于实际项目中。 ### 一、Netty简介与核心特性 Netty...

    Netty源码阅读笔记

    以上内容便是Netty源码阅读笔记中提到的主要知识点。这些知识点构成了Netty框架的核心,涵盖了从数据容器到事件处理,再到粘包半包问题处理的完整流程。了解和掌握这些知识点对于深入使用Netty进行网络编程具有重要...

    Netty核心精讲之Reactor线程模型源码分析.mp4

    Netty的源码分析中,我们会关注以下几个关键点: 1. `NioEventLoop`:这是Netty针对Java NIO实现的EventLoop类,其中包含了对选择器(Selector)的管理和事件的分发。 2. `ChannelHandlerContext`:它是Netty的上...

    Netty框架源码(并且有详细的注释)

    Netty是一个高性能、异步事件驱动的网络应用框架...总的来说,这个压缩包提供了一个深入学习Netty源码的机会,通过阅读和实践,开发者能够掌握Netty的设计理念,提升网络编程的能力,并能根据需求定制自己的网络框架。

    java Netty 框架例子源码.rar

    Java Netty 是一个高性能、异步...通过分析这些示例源码,我们可以深入理解 Netty 的工作原理,掌握如何在实际项目中构建高性能的网络应用。同时,这也将有助于我们了解如何处理异常、实现安全性以及优化网络通信性能。

    netty源码阅读笔记.pdf

    1. **Netty源码分析系列文章**:这部分内容可能涵盖了Netty的整体架构、核心组件以及关键算法的解析,包括线程模型、缓冲区管理、事件驱动模型等方面。作者可能从整体上介绍了Netty的设计原则和实现方式。 2. **...

    netty权威指南 源码

    此外,源码分析有助于我们了解 Netty 如何处理网络事件、协议解析、线程调度等核心问题,对于提高开发水平和解决实际问题大有裨益。 书中可能涵盖了以下主题: - Netty 的设计理念和架构 - 异步事件驱动模型的实现...

    Netty3.x 源码解析

    由于Netty源码较庞大,所以文章建议通过分析几个关键组件来构建对整个框架的理解,从而避免在庞大的源码海洋中迷失方向。通过理解Netty的关键点,包括NIO的使用、事件处理机制、ChannelPipeline的运作以及Handler的...

    咕泡学院_Tom_JavaVIP课程_深入分析Netty源码1

    JavaVIP课程深入分析了Netty源码,由Tom老师主讲,主要针对咕泡学院的高级Java学员。本文档详细探讨了Netty框架的核心组件及其使用,特别关注了BootStrap类在客户端和服务器端的角色。 BootStrap是Netty提供的一种...

    netty4.1源码

    源码分析中,你可以关注以下几个关键部分: - **Channel**:这是Netty中的基本抽象,代表一个网络连接,可以是服务器端的监听套接字,也可以是客户端的连接。 - **EventLoop**:每个Channel都会绑定到一个EventLoop...

    netty实战源码

    这个“Netty 实战源码”压缩包很可能是为了帮助开发者深入理解 Netty 的工作原理和实现机制,通过源码分析来提升对网络编程的理解。 Netty 的核心特性包括: 1. **异步事件驱动**:Netty 使用非阻塞 I/O(NIO)...

    netty5.0源码包的依赖包

    通过分析ChannelPipeline,我们可以理解事件在Channel之间的传递机制。 依赖包的源码同样重要,因为Netty依赖于一些第三方库来完成特定功能。例如,依赖的Apache Commons Logging用于日志记录,Google的Guava库提供...

    Netty权威指南第二版源码

    源码分析可以帮助理解这两者之间的交互,以及如何优雅地处理并发和多线程问题。 3. **ByteBuf**:Netty的自定义缓冲区类,提供了高效的数据读写和内存管理。通过源码,可以学习到如何优化数据传输和避免不必要的...

    Netty源码解析-服务启动过程.pdf

    ### Netty源码解析——服务启动过程 #### 一、Netty概述 Netty是一个高性能、异步事件驱动的网络应用框架,它被广泛应用于快速开发高性能协议服务器和客户端。Netty通过高度优化的设计和实现提供了低延迟和高吞吐...

Global site tag (gtag.js) - Google Analytics