5. Netty源码分析之ChannelPipeline 和 ChannelHanler

Posted lovezmc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5. Netty源码分析之ChannelPipeline 和 ChannelHanler相关的知识,希望对你有一定的参考价值。

前言:ChannelPipeline和ChannelHandler是类似于Spring拦截器的一种实现,数据在pipeline中传播,每个ChannelHandler处理自己感兴趣的部分。

一、ChannelPipeline

  ChannelPipeline是ChannelHandler的容器,负责ChannelHandler的管理和事件拦截及调度。

1. ChannelPipeline的事件处理

1. 读操作(InBound):NioEventLoop调用ChannelPipeline的fireChannelRead(..)方法,将消息传输到ChannelPipeline中。Channelhandler处理流程:HeadHandler -> ChannelHandler1 -> .. -> ChannelHandlerN -> TailHandler

2. 写操作(OutBound):调用ChannelHandlerContext的write方法发送消息,经过handler处理后,最终被添加到消息发送缓冲区等待刷新和发送。ChannelHandler处理流程:TailHandler -> ChannelHandlerN -> ... -> ChannelHandler1 -> HeadHandler

 

这里提到了InBound 和 OutBound,顾名思义,InBound就是指进来,例如read、accept这些,都是IO操作往内部方向进行的;OutBound就是指出去,例如connect、write、flush这些,都是IO操作往外部方向进行的。

技术图片

 2. ChannelPipeline源码分析

  ChannelPipeline实际上是一个ChannelHandler管理容器,它的内部维护了一个ChannelHandler的链表和迭代器,可以方便的增删改查ChannelHandler。

我们看一下addBefore方法,这里先后校验了handler不允许多个ChannelPipeline共享、handlerName不能重复、基准handler不能为null,最后把新增的handler放在基准handler之前,最后触发handlerAdded事件。

public final ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler) 
    return addBefore(null, baseName, name, handler);


public final ChannelPipeline addBefore(EventExecutorGroup group, String baseName, String name, ChannelHandler handler) 
    final AbstractChannelHandlerContext newCtx;
    final AbstractChannelHandlerContext ctx;
    synchronized (this) 
        //Channdler不允许多个ChannelPipeline共享
        checkMultiplicity(handler);
        // 1. 如果name为空则生成一个name,2.name不允许重复
        name = filterName(name, handler);
        // 根据basic查询要插入到哪个Handler之前,如果不存在,则抛异常
        ctx = getContextOrDie(baseName);
        // 创建DefaultChannelHandlerContext对象
        newCtx = newContext(group, name, handler);
        
        // 把它加在ctx前面,就是简单的链表插入操作
        addBefore0(ctx, newCtx);

        // 当注册暂未成功时,添加一个handlerAdded任务,当注册成功时调用
        if (!registered) 
            newCtx.setAddPending();
            callHandlerCallbackLater(newCtx, true);
            return this;
        
        
        // 如果当前线程不是EventLoop线程,则放进EventLoop队列中执行handlerAdded
        EventExecutor executor = newCtx.executor();
        if (!executor.inEventLoop()) 
            callHandlerAddedInEventLoop(newCtx, executor);
            return this;
        
    
    // 执行handlerAdded
    callHandlerAdded0(newCtx);
    return this;


private static void addBefore0(AbstractChannelHandlerContext ctx, AbstractChannelHandlerContext newCtx) 
    newCtx.prev = ctx.prev;
    newCtx.next = ctx;
    ctx.prev.next = newCtx;
    ctx.prev = newCtx;

二、ChannelHandler

  ChannelHandler类似于Spring的拦截器,负责对IO事件或IO操作进行拦截和处理,它可以选择性的拦截和处理自己感兴趣的事件,也可以透传和终止事件的传递。

  ChannelHandler的实现类很多,这里主要说一下ChannelHandlerAdapter。

  对于大多数的ChannelHandler而言,都会选择性的拦截自己感兴趣的事件,如果直接实现ChannelHandler,就需要写过多与自己无关的方法。而2ChannelHandlerAdapter实现了ChannelHandler所有的方法,但是所有的实现都是透传,我们只需要继承ChannelHandlerAdapter,覆写自己感兴趣的事件即可。

 

以上是关于5. Netty源码分析之ChannelPipeline 和 ChannelHanler的主要内容,如果未能解决你的问题,请参考以下文章

2. Netty源码分析之使用篇

Netty4.xNetty源码分析之LineBasedFrameDecoder

Netty源码分析之服务端启动

8. Netty源码分析之ByteBuf

#yyds干货盘点# Netty源码分析之Reactor线程模型详解

4. Netty源码分析之Unsafe