ChannelPipeline类似于一个管道,管道中存放的是一系列对读取数据进行业务操作的ChannelHandler。

1、ChannelPipeline的结构图:

在之前的博客【Netty源码学习】入门示例我们看到了如下的代码:

future.channel().writeAndFlush("Hello Netty Server ,I am a common client");  

其实就是Client向Server发送数据,其具体实现是在AbstractChannel类中

@Override
    public ChannelFuture writeAndFlush(Object msg) {
        return pipeline.writeAndFlush(msg);
    }

上面这段代码出现了我们这篇博客要分析的类DefaultChannelPipeline,其是ChannelPipeline的实现类。DefaultChannelPipeline中writeAndFlush(msg)的实现如下:

@Override
    public final ChannelFuture writeAndFlush(Object msg) {
        return tail.writeAndFlush(msg);
    }

tail对象的定义如下final AbstractChannelHandlerContext tail,接口为ChannelHandlerContext我们会接下来进行分析,其进一步封装了数据读写操作。现在看好像DefaultChannelPipeline的使命已经结束了,发送数据的操作在AbstractChannelHandlerContext中实现。

接下来我们详细介绍一下DefaultChannelPipeline,一开始我们说它是一个管道,是因为他的名称是pipe,其实现在看来他更像一个链表(其实是一个双向循环链表),队列的单位是AbstractChannelHandlerContext,因为其定义了两个变量。

final AbstractChannelHandlerContext head;
    final AbstractChannelHandlerContext tail;

head为链表的头,tail为链表的尾,接下来的很多操作都与head和tail相关的。添加ChannelHandler操作。

@Override
    public final ChannelPipeline addFirst(String name, ChannelHandler handler) {
        return addFirst(null, name, handler);
    }

    @Override
    public final ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized (this) {
            checkMultiplicity(handler);
            name = filterName(name, handler);

            newCtx = newContext(group, name, handler);

            addFirst0(newCtx);

            // If the registered is false it means that the channel was not registered on an eventloop yet.
            // In this case we add the context to the pipeline and add a task that will call
            // ChannelHandler.handlerAdded(...) once the channel is registered.
            if (!registered) {
                newCtx.setAddPending();
                callHandlerCallbackLater(newCtx, true);
                return this;
            }

            EventExecutor executor = newCtx.executor();
            if (!executor.inEventLoop()) {
                newCtx.setAddPending();
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        callHandlerAdded0(newCtx);
                    }
                });
                return this;
            }
        }
        callHandlerAdded0(newCtx);
        return this;
    }

    private void addFirst0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext nextCtx = head.next;
        newCtx.prev = head;
        newCtx.next = nextCtx;
        head.next = newCtx;
        nextCtx.prev = newCtx;
    }

在addFirst0中我们可以清晰的看到,创建双向循环对列,对列的基本单位是AbstractChannelHanndlerContext。ChannelPipeline继承ChannelInboundInvoker和ChannelOutboundInvoker,它既是一个inboundinvoke,又是一个outboundinvoke,同时也是ChannelChandler的管理者,提供了很多对handler进行的操作。

我们介绍一下channelActive操作channelActive函数

@Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelActive();

            readIfIsAutoRead();
        }

其具体实现在我们继承的ChannelHandlerContext类中,比如我们入门教程中的ClientHandler中

@Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("HelloWorldClientHandler Active");
    }  

由于ChannelHandlerContext是实现数据读写的具体操作类,DefaultChannelPipeline实现了一个ChannelHandlerContext的双向链表,ChannelHandlerContext中封装了我们对消息数据的具体操作比如ClientHandler打印数据,因此DefaultChannelPipeplie的双向链表就是对数据的各种操作,所以在很多地方都会看到pipeline的身影。

最新文章

  1. [SQLServer大对象]——FileTable从文件系统迁移文件
  2. dedecms数据库表前缀不一样怎么还原数据
  3. PHP中文字符串编码转换
  4. HDU 4121
  5. CentOS 7 x64 安装 Ceph
  6. Raphael的transform用法
  7. 消息映射(C++)(转)
  8. hibernate 使用枚举字段的最佳实践
  9. mime类型的解析与应用
  10. LOJ 2409「THUPC 2017」小 L 的计算题 / Sum
  11. Tomcat8-windows不能在本地计算机启动tomcat,有更多的信息,查阅系统事件日志。
  12. TCP简介(一)
  13. Linux目录路径知识
  14. Subversion客户端接受服务器证书出现“The certificate hostname does not match”的问题
  15. delphi JPG或BMP图片透明显示
  16. 『cs231n』作业3问题1选讲_通过代码理解RNN&图像标注训练
  17. nyoj 单调递增子序列(二)
  18. 不要怂,就是GAN (生成式对抗网络) (五):无约束条件的 GAN 代码与网络的 Graph
  19. 阿里云服务器之hexo环境搭建
  20. php如何判断两个时间的时间差

热门文章

  1. [ZJOI2008]生日聚会
  2. 洛谷P3980:[NOI2008]志愿者招募
  3. 【poj 1087 a plug for UNIX】
  4. jqGrid移动滑块时冻结首列和第二列例子
  5. Spring系列之装配Bean
  6. 图像融合之拉普拉斯融合(laplacian blending)
  7. php+xdebug远程调试(单人)
  8. chrome不支持embed标签解决方案
  9. JS中怎样判断undefined(比较不错的方法)
  10. Mysql--存储引擎(MyISam & InnoDB)