Netty Channel 源码分析

254 阅读3分钟

这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

前言

首先,我们要明白 Channel、ChannelHandler、ChannelPipe 这几个关键组件的关系。

Channel 就跟 BIO 中流(Stream) 一样是用来传输数据的,每一个客户端都会有一个 Channel;而每个 Channel 都包含了一个管道 ChannelPipeline;ChannelPipeline 提供了 ChannelHandler 的容器,可以理解成一个双向链表 -- 责任链模式。

Image.png

pipeline职责连

为请求创建一个处理对象的链, 责任链模式使用的场景比较多比如我们熟悉的sential核心的规则处理, 我们平常业务处理比如营销中各种营销规则的优先级等,都可以采取这种责任链的模式。 image.png

Channel源码分析

Channel主要继承关系图

服务端 NioServerSocketChannel 类的继承关系图

Channel.png

客户端 NioSocketChannel

NioSocketChannel.png

AbstractChannel

AbstractChannel内部有一个pipeline属性,Netty在对Channel进行初始化的时候将该属性初始化为DefaultChannelPipeline的实例

protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();
    unsafe = newUnsafe();
    pipeline = newChannelPipeline();
}

AbstractChannel#newChannelPipeline

protected DefaultChannelPipeline newChannelPipeline() {
    return new DefaultChannelPipeline(this);
}

protected DefaultChannelPipeline(Channel channel) {
    this.channel = ObjectUtil.checkNotNull(channel, "channel");
    succeededFuture = new SucceededChannelFuture(channel, null);
    voidPromise =  new VoidChannelPromise(channel, true);

    tail = new TailContext(this);
    head = new HeadContext(this);

    head.next = tail;
    tail.prev = head;
}

TailContext , HeadContext 这个就是我们上面说的责任链头尾指针

*                                                 I/O Request
*                                            via {@link Channel} or
*                                        {@link ChannelHandlerContext}
*                                                      |
*  +---------------------------------------------------+---------------+
*  |                           ChannelPipeline         |               |
*  |                                                  |/              |
*  |    +---------------------+            +-----------+----------+    |
*  |    | Inbound Handler  N  |            | Outbound Handler  1  |    |
*  |    +----------+----------+            +-----------+----------+    |
*  |              /|\                                  |               |
*  |               |                                  |/              |
*  |    +----------+----------+            +-----------+----------+    |
*  |    | Inbound Handler N-1 |            | Outbound Handler  2  |    |
*  |    +----------+----------+            +-----------+----------+    |
*  |              /|\                                  .               |
*  |               .                                   .               |
*  | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
*  |        [ method call]                       [method call]         |
*  |               .                                   .               |
*  |               .                                  |/              |
*  |    +----------+----------+            +-----------+----------+    |
*  |    | Inbound Handler  2  |            | Outbound Handler M-1 |    |
*  |    +----------+----------+            +-----------+----------+    |
*  |              /|\                                  |               |
*  |               |                                  |/              |
*  |    +----------+----------+            +-----------+----------+    |
*  |    | Inbound Handler  1  |            | Outbound Handler  M  |    |
*  |    +----------+----------+            +-----------+----------+    |
*  |              /|\                                  |               |
*  +---------------+-----------------------------------+---------------+
*                  |                                  |/
*  +---------------+-----------------------------------+---------------+
*  |               |                                   |               |
*  |       [ Socket.read() ]                    [ Socket.write() ]     |
*  |                                                                   |
*  |  Netty Internal I/O Threads (Transport Implementation)            |
*  +-------------------------------------------------------------------+

inbound事件的流行是从下至上, 而outbound刚好相反,是从上到下。同时注释中列出了引发inbound事件和outbound事件传播的方法:

* <li>Inbound event propagation methods:
*     <ul>
*     <li>{@link ChannelHandlerContext#fireChannelRegistered()}</li>
*     <li>{@link ChannelHandlerContext#fireChannelActive()}</li>
*     <li>{@link ChannelHandlerContext#fireChannelRead(Object)}</li>
*     <li>{@link ChannelHandlerContext#fireChannelReadComplete()}</li>
*     <li>{@link ChannelHandlerContext#fireExceptionCaught(Throwable)}</li>
*     <li>{@link ChannelHandlerContext#fireUserEventTriggered(Object)}</li>
*     <li>{@link ChannelHandlerContext#fireChannelWritabilityChanged()}</li>
*     <li>{@link ChannelHandlerContext#fireChannelInactive()}</li>
*     <li>{@link ChannelHandlerContext#fireChannelUnregistered()}</li>
*     </ul>
* </li>
* <li>Outbound event propagation methods:
*     <ul>
*     <li>{@link ChannelHandlerContext#bind(SocketAddress, ChannelPromise)}</li>
*     <li>{@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)}</li>
*     <li>{@link ChannelHandlerContext#write(Object, ChannelPromise)}</li>
*     <li>{@link ChannelHandlerContext#flush()}</li>
*     <li>{@link ChannelHandlerContext#read()}</li>
*     <li>{@link ChannelHandlerContext#disconnect(ChannelPromise)}</li>
*     <li>{@link ChannelHandlerContext#close(ChannelPromise)}</li>
*     <li>{@link ChannelHandlerContext#deregister(ChannelPromise)}</li>
*     </ul>
* </li>

业务代码中责任链模式应用

image.png

责任链框架

public interface SlotChainBuilder<T> {

    /**
     * 构造器
     * @return
     */
    T build();
}
public interface ProcessorSlot<T> {
    /**
     * 前置处理方法
     */
    void process(T param);

    /**
     * 触发下一个
     * @param param
     */
    void fireProcess(T param);
}


public abstract class ProcessorSlotChain<T> extends AbstractLinkedProcessorSlot<T> {


    /**
     * 添加到下一个触发节点
     * @param processorSlot
     */
    public abstract void addLast(AbstractLinkedProcessorSlot<T> processorSlot);
}


public class DefaultProcessorSlotChain<T> extends ProcessorSlotChain<T> {

    //初始化头检点
    AbstractLinkedProcessorSlot<T> first = new AbstractLinkedProcessorSlot<T>() {
        @Override
        public void processHandler(T param) {
            //不做处理
        }
    };

    AbstractLinkedProcessorSlot<T> end = first;


    @Override
    public void processHandler(T param) {
        //初始化头节点
        setNext(first);
    }

    @Override
    public void addLast(AbstractLinkedProcessorSlot<T> processorSlot) {
        //设置下一个节点
        end.setNext(processorSlot);
        //指针就指向下一个节点
        end = processorSlot;
    }
}


public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> {

    /**
     * 设置链的下一个触发的组件
     */
    private AbstractLinkedProcessorSlot<T> next = null;

    @Override
    public void fireProcess(T param) {
        if(next != null){
            //触发下一个节点执行
            next.process(param);
        }
    }

    public AbstractLinkedProcessorSlot<T> getNext() {
        return next;
    }

    public void setNext(AbstractLinkedProcessorSlot<T> next) {
        this.next = next;
    }

    @Override
    public void process(T param) {

        processHandler(param);
        //触发下一个节点进行
        fireProcess(param);

    }

    /**
     * 定义钩子,是业务逻辑实际处理的实现
     * @param param
     */
    public abstract void processHandler(T param);
}

业务builder和节点

CheckerSlotChainBuilder

@Component
public class CheckerSlotChainBuilder implements SlotChainBuilder<ProcessorSlotChain> {

    @Resource
    private RepeatMobileCheckerSlot repeatMobileCheckerSlot;

    @Resource
    private TinyUrlValidatorSlot tinyUrlValidatorSlot;


    @Override
    public ProcessorSlotChain build() {
        ProcessorSlotChain chain = new DefaultProcessorSlotChain();
        chain.addLast(tinyUrlValidatorSlot);
        chain.addLast(repeatMobileCheckerSlot);
        return chain;
    }
}


@Component
@Slf4j
public class RepeatMobileCheckerSlot extends AbstractLinkedProcessorSlot<SmsSendContext> {
    @Override
    public void processHandler(SmsSendContext param) {
        log.info("重复手机号码校验:任务ID:{}", param.getTaskId());
    }
}


@Component
@Slf4j
public class TinyUrlValidatorSlot extends AbstractLinkedProcessorSlot<SmsSendContext> {
    @Override
    public void processHandler(SmsSendContext param) {
        log.info("校验短信群发任务中短链接的有效性,url:{}", param.getUrl());
    }
}

image.png