Netty源碼分析之ChannelPipeline

本章節分析Netty中的ChannelPipeline模塊。

每個channel內部都會持有一個ChannelPipeline對象pipeline.
pipeline默認實現DefaultChannelPipeline內部維護了一個DefaultChannelHandlerContext鏈表。

ChannelPipeline

當channel完成register、active、read等操作時,會觸發pipeline的相應方法。
1、當channel注冊到selector時,觸發pipeline的fireChannelRegistered方法。
2、當channel的socket綁定完成時,觸發pipeline的fireChannelActive方法。
3、當有客戶端請求時,觸發pipeline的fireChannelRead方法。
4、當本次客戶端請求,pipeline執行完fireChannelRead,觸發pipeline的fireChannelReadComplete方法。

接下去看看pipeline是如何組織并運行handler對應的方法。

DefaultChannelPipeline

其中DefaultChannelHandlerContext保存了當前handler的上下文,如channel、pipeline等信息,默認實現了head和tail。

class DefaultChannelPipeline implements ChannelPipeline {
    final Channel channel; // pipeline所屬的channel
    //head和tail都是handler上下文
    final DefaultChannelHandlerContext head;
    final DefaultChannelHandlerContext tail;
    ...
    public DefaultChannelPipeline(AbstractChannel channel) {
        if (channel == null) {
            throw new NullPointerException("channel");
        }
        this.channel = channel;

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

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

1、TailContext實現了ChannelOutboundHandler接口。
2、HeadContext實現了ChannelInboundHandler接口。
3、head和tail形成了一個鏈表。

對于Inbound的操作,當channel注冊到selector時,觸發pipeline的fireChannelRegistered,從head開始遍歷,找到實現了ChannelInboundHandler接口的handler,并執行其fireChannelRegistered方法。

@Override
public ChannelPipeline fireChannelRegistered() {
    head.fireChannelRegistered();
    return this;
}

@Override
public ChannelHandlerContext fireChannelRegistered() {
    final DefaultChannelHandlerContext next = findContextInbound();
    EventExecutor executor = next.executor();
    if (executor.inEventLoop()) {
        next.invokeChannelRegistered();
    } else {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                next.invokeChannelRegistered();
            }
        });
    }
    return this;
}

private DefaultChannelHandlerContext findContextInbound() {
    DefaultChannelHandlerContext ctx = this;
    do {
        ctx = ctx.next;
    } while (!(ctx.handler() instanceof ChannelInboundHandler));
    return ctx;
}

private void invokeChannelRegistered() {
    try {
        ((ChannelInboundHandler) handler()).channelRegistered(this);
    } catch (Throwable t) {
        notifyHandlerException(t);
    }
}

假如我們通過pipeline的addLast方法添加一個inboundHandler實現。

public class ClientHandler extends ChannelInboundHandlerAdapter {
    @Override  
    public void channelRegistered(ChannelHandlerContext ctx)  
            throws Exception {  
        super.channelRegistered(ctx);  
        System.out.println(" ClientHandler  registered channel ");  
    }  
}  

當channel注冊完成時會觸發pipeline的channelRegistered方法,從head開始遍歷,找到ClientHandler,并執行channelRegistered方法。

對于Outbound的操作,則從tail向前遍歷,找到實現ChannelOutboundHandler接口的handler,具體實現和Inbound一樣。

服務啟動過程中,ServerBootstrap在init方法中,會給ServerSocketChannel的pipeline添加ChannelInitializer對象,其中ChannelInitializer繼承ChannelInboundHandlerAdapter,并實現了ChannelInboundHandler接口,所以當ServerSocketChannel注冊到selector之后,會觸發其channelRegistered方法。

public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    initChannel((C) ctx.channel());
    ctx.pipeline().remove(this);
    ctx.fireChannelRegistered();
}

public void initChannel(Channel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
    ChannelHandler handler = handler();
    if (handler != null) {
        pipeline.addLast(handler);
    }
    pipeline.addLast(new ServerBootstrapAcceptor(
            currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}

在initChannel實現中,添加ServerBootstrapAcceptor實例到pipeline中。

ServerBootstrapAcceptor繼承自ChannelInboundHandlerAdapter,負責把接收到的客戶端socketChannel注冊到childGroup中,由childGroup中的eventLoop負責數據處理。

public void channelRead(ChannelHandlerContext ctx, Object msg) {
    final Channel child = (Channel) msg;

    child.pipeline().addLast(childHandler);

    for (Entry<ChannelOption<?>, Object> e: childOptions) {
        try {
            if (!child.config().setOption((ChannelOption<Object>) e.getKey(), e.getValue())) {
                logger.warn("Unknown channel option: " + e);
            }
        } catch (Throwable t) {
            logger.warn("Failed to set a channel option: " + child, t);
        }
    }

    for (Entry<AttributeKey<?>, Object> e: childAttrs) {
        child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
    }

    try {
        childGroup.register(child).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                if (!future.isSuccess()) {
                    forceClose(child, future.cause());
                }
            }
        });
    } catch (Throwable t) {
        forceClose(child, t);
    }
}

END。
我是占小狼。
在魔都艱苦奮斗,白天是上班族,晚上是知識服務工作者。
如果讀完覺得有收獲的話,記得關注和點贊哦。
非要打賞的話,我也是不會拒絕的。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容