成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

Netty4.x 源碼實(shí)戰(zhàn)系列(四):Pipeline全剖析

13651657101 / 2633人閱讀

摘要:在上一篇源碼實(shí)戰(zhàn)系列三全剖析中,我們?cè)敿?xì)分析了的初始化過(guò)程,并得出了如下結(jié)論在中,每一個(gè)都有一個(gè)對(duì)象,并且其內(nèi)部本質(zhì)上就是一個(gè)雙向鏈表本篇我們將深入源碼內(nèi)部,對(duì)其一探究竟,給大家一個(gè)全方位解析。

在上一篇《Netty4.x 源碼實(shí)戰(zhàn)系列(三):NioServerSocketChannel全剖析》中,我們?cè)敿?xì)分析了NioServerSocketChannel的初始化過(guò)程,并得出了如下結(jié)論:

在netty中,每一個(gè)channel都有一個(gè)pipeline對(duì)象,并且其內(nèi)部本質(zhì)上就是一個(gè)雙向鏈表

本篇我們將深入Pipeline源碼內(nèi)部,對(duì)其一探究竟,給大家一個(gè)全方位解析。

Pipeline初始化過(guò)程分析

在上一篇中,我們得知channel中的pipeline其實(shí)就是DefaultChannelPipeline的實(shí)例,首先我們先看看DefaultChannelPipeline的類(lèi)繼承結(jié)構(gòu)圖:

根據(jù)類(lèi)繼承結(jié)構(gòu)圖,我們看到DefaultChannelPipeline實(shí)現(xiàn)了 ChannelInboundInvoker及ChannelOutboundInvoker兩個(gè)接口。
顧名思義,一個(gè)是處理通道的inbound事件調(diào)用器,另一個(gè)是處理通道的outbound事件調(diào)用器。

inbound: 本質(zhì)上就是執(zhí)行I/O線(xiàn)程將從外部read到的數(shù)據(jù) 傳遞給 業(yè)務(wù)線(xiàn)程的一個(gè)過(guò)程。
outbound: 本質(zhì)上就是業(yè)務(wù)線(xiàn)程 將數(shù)據(jù) 傳遞給I/O線(xiàn)程, 直至發(fā)送給外部的一個(gè)過(guò)程。

如下圖所示:

我們?cè)倩氐紻efaultChannelPipeline這個(gè)類(lèi),看看其構(gòu)造方法:

protected DefaultChannelPipeline(Channel channel) {
    // 通道綁定channel對(duì)象
    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;
}

此構(gòu)造方法主要做了三件事:
1、綁定了當(dāng)前NioServerSocketChannel實(shí)例
2、初始化pipeline雙向鏈表的頭、尾節(jié)點(diǎn)

關(guān)于NioServerSocketChannel,我在前一篇中已經(jīng)做過(guò)詳細(xì)描述,現(xiàn)在我們著重看看head及tail這兩個(gè)屬性。

從上面的構(gòu)造方法得知,head是HeadContext的實(shí)例,tail是TailContext的實(shí)例,HeadContext與TailContext都是DefaultChannelPipeline的內(nèi)部類(lèi),它們的類(lèi)繼承結(jié)構(gòu)圖如下:

HeadContext類(lèi)繼承結(jié)構(gòu)圖

TailContext類(lèi)繼承結(jié)構(gòu)圖

從類(lèi)繼承圖我們可以看出:
1、HeadContext與TailContext都是通道的handler(中文一般叫做處理器)
2、HeadContext既可以用于outbound過(guò)程的handler,也可以用于inbound過(guò)程的handler (關(guān)于inboun和outbound上面已經(jīng)作了解釋)
3、TailContext只可以用于inbound過(guò)程的handler
4、HeadContext 與 TailContext 同時(shí)也是一個(gè)處理器上下文對(duì)象

下面我將以HeadContext為例,看看它初始化過(guò)程中到底作了哪些工作

head = new HeadContext(this);

在DefaultChannelPipeline的構(gòu)造方法中,我們看到head結(jié)點(diǎn)初始化代碼如上面所示,對(duì)應(yīng)構(gòu)造器代碼如下:

HeadContext(DefaultChannelPipeline pipeline) {
    super(pipeline, null, HEAD_NAME, false, true);
    unsafe = pipeline.channel().unsafe();
    setAddComplete();
}

在其內(nèi)部,它會(huì)繼續(xù)調(diào)用父類(lèi)AbstractChannelHandlerContext的構(gòu)造器

AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
                                  boolean inbound, boolean outbound) {
        this.name = ObjectUtil.checkNotNull(name, "name");
        this.pipeline = pipeline;
        this.executor = executor;
        this.inbound = inbound;
        this.outbound = outbound;
        
        ordered = executor == null || executor instanceof OrderedEventExecutor;
    }

此構(gòu)造方法,只是設(shè)置了當(dāng)前context對(duì)象對(duì)應(yīng)的Pipeline以及此context是作用于outbound。
AbstractChannelHandlerContext類(lèi)還有另外兩個(gè)額外屬性,他們是實(shí)現(xiàn)雙向鏈表的關(guān)鍵:

volatile AbstractChannelHandlerContext next;  // 指定下一個(gè)結(jié)點(diǎn)
volatile AbstractChannelHandlerContext prev;  // 指定前一個(gè)結(jié)點(diǎn)

HeadContext 同時(shí)還綁定了unsafe對(duì)象,我們?cè)倩仡櫼幌聈nsafe對(duì)象。

我們從上一篇已經(jīng)得知 unsafe其實(shí)就是對(duì)java nio 通道底層調(diào)用進(jìn)行的封裝,就相當(dāng)于一個(gè)代理類(lèi)對(duì)象。

而DefaultChannelPipeline初始化時(shí),已經(jīng)綁定了channel,且由于是服務(wù)端,所以此channel是NioServerSocketChannel

protected DefaultChannelPipeline(Channel channel) {
    // 通道綁定channel對(duì)象
    this.channel = ObjectUtil.checkNotNull(channel, "channel");
    
    ... //非相關(guān)代碼已省略
}

所以

unsafe = pipeline.channel().unsafe();

就是

unsafe = new NioMessageUnsafe();

關(guān)于pipeline的tail結(jié)點(diǎn)初始化過(guò)程跟head差不多,這里就不作贅述了。

階段性總結(jié): 
1、每個(gè)channel初始化時(shí),都會(huì)創(chuàng)建一個(gè)與之對(duì)應(yīng)的pipeline;
2、此pipeline內(nèi)部就是一個(gè)雙向鏈表;
3、雙向鏈表的頭結(jié)點(diǎn)是處理outbound過(guò)程的handler,尾節(jié)點(diǎn)是處理inbound過(guò)程的handler;
4、雙向鏈表的結(jié)點(diǎn)同時(shí)還是handler上下文對(duì)象;
Pipeline在服務(wù)端bind過(guò)程中的應(yīng)用

通過(guò)《Netty4.x 源碼實(shí)戰(zhàn)系列(二):服務(wù)端bind流程詳解》 一文,我們知道,服務(wù)端channel在初始化過(guò)程中,會(huì)調(diào)用addLast方法,并傳遞了一個(gè)ChannelInitializer對(duì)象

@Override
void init(Channel channel) throws Exception {
    
    // 非相關(guān)代碼已省略
    ChannelPipeline p = channel.pipeline();
    
    p.addLast(new ChannelInitializer() {
        @Override
        public void initChannel(final Channel ch) throws Exception {
            final ChannelPipeline pipeline = ch.pipeline();
            ChannelHandler handler = config.handler();
            if (handler != null) {
                pipeline.addLast(handler);
            }

            ch.eventLoop().execute(new Runnable() {
                @Override
                public void run() {
                    pipeline.addLast(new ServerBootstrapAcceptor(
                            ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                }
            });
        }
    });
}

本節(jié)我們將詳細(xì)分析一下addLast的過(guò)程 與 ChannelInitializer。

ChannelInitializer
我們先看一下ChannelInitializer的類(lèi)繼承結(jié)構(gòu)圖

通過(guò)類(lèi)繼承圖,我們得知ChannelInitializer的匿名對(duì)象其實(shí)就是一個(gè)處理inbound過(guò)程的處理器,與pipeline中的tail一樣,目前稍有不同的就是ChannelInitializer的匿名對(duì)象并不是一個(gè)context對(duì)象。

關(guān)于ChannelInitializer匿名對(duì)象的initChannel方法實(shí)現(xiàn)的內(nèi)容,本篇先不作詳述,當(dāng)講到EventLoop時(shí),我們?cè)賮?lái)回顧一下。

pipeline.addLast方法

addLast具體實(shí)現(xiàn)如下:

@Override
public final ChannelPipeline addLast(ChannelHandler... handlers) {
    return addLast(null, handlers);
}

通過(guò)此方法參數(shù),我們也可以得出,init(Channel channel)方法中的addLast其實(shí)就是想Pipeline中添加一個(gè)處理器。
addLast內(nèi)部繼續(xù)調(diào)用另一個(gè)重載方法:

@Override
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
    if (handlers == null) {
        throw new NullPointerException("handlers");
    }

    for (ChannelHandler h: handlers) {
        if (h == null) {
            break;
        }
        addLast(executor, null, h);
    }

    return this;
}

最終調(diào)用的是下面的重載方法(已省略非相關(guān)代碼):

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

        newCtx = newContext(group, filterName(name, handler), handler);

        addLast0(newCtx);

        
    }
    
    return this;
}

newContext方法的作用就是對(duì)傳入的handler進(jìn)行包裝,最后返回一個(gè)綁定了handler的context對(duì)象:

private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
    return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}

新的對(duì)象是DefaultChannelHandlerContext類(lèi)的實(shí)例。

接著我們?cè)倏纯碼ddLast0方法

private void addLast0(AbstractChannelHandlerContext newCtx) {
    AbstractChannelHandlerContext prev = tail.prev;
    newCtx.prev = prev;
    newCtx.next = tail;
    prev.next = newCtx;
    tail.prev = newCtx;
}

經(jīng)過(guò)addLast0,新包裝的context已經(jīng)添加至pipeline中了,此時(shí)的pipeline結(jié)果變化過(guò)程如下:

從addLast0代碼片段得知, 每個(gè)新添加的結(jié)點(diǎn),都是從tail結(jié)點(diǎn)之前插入

本篇總結(jié):
經(jīng)過(guò)本篇的代碼研究,對(duì)于Pipeline得出以下結(jié)論:
1、channel初始化時(shí),會(huì)同時(shí)創(chuàng)建一個(gè)與之對(duì)應(yīng)的pipeline;
2、此pipeline本質(zhì)上是一個(gè)handler處理器雙向鏈表, 用于將處理inbound及outbound過(guò)程的handler都串聯(lián)起來(lái);
3、在netty中,對(duì)于I/O處理分為兩種流向,對(duì)于獲取外部數(shù)據(jù)資源進(jìn)行處理的,都是對(duì)應(yīng)inbound,比如read等,而對(duì)于向外部發(fā)送數(shù)據(jù)資源的,都對(duì)于outbound,比如connetct及write等。

關(guān)于pipeline中的handler調(diào)用過(guò)程,后面的章節(jié)我們會(huì)做詳細(xì)分析。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/68101.html

相關(guān)文章

  • Netty4.x 源碼實(shí)戰(zhàn)系列(二):服務(wù)端bind流程詳解

    摘要:對(duì)于,目前大家只知道是個(gè)線(xiàn)程組,其內(nèi)部到底如何實(shí)現(xiàn)的,它的作用到底是什么,大家也都不太清楚,由于篇幅原因,這里不作詳細(xì)介紹,后面會(huì)有文章作專(zhuān)門(mén)詳解。 在上一篇《ServerBootstrap 與 Bootstrap 初探》中,我們已經(jīng)初步的了解了ServerBootstrap是netty進(jìn)行服務(wù)端開(kāi)發(fā)的引導(dǎo)類(lèi)。 且在上一篇的服務(wù)端示例中,我們也看到了,在使用netty進(jìn)行網(wǎng)絡(luò)編程時(shí),我...

    laoLiueizo 評(píng)論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列(三):NioServerSocketChannel剖析

    摘要:本篇將通過(guò)實(shí)例化過(guò)程,來(lái)深入剖析。及初始化完成后,它們會(huì)相互連接。我們?cè)诨氐降臉?gòu)造方法父類(lèi)構(gòu)造方法調(diào)用完成后,還要初始化一下自己的配置對(duì)象是的內(nèi)部類(lèi)而又是繼承自,通過(guò)代碼分析,此對(duì)象就是就會(huì)對(duì)底層一些配置設(shè)置行為的封裝。 根據(jù)上一篇《Netty4.x 源碼實(shí)戰(zhàn)系列(二):服務(wù)端bind流程詳解》所述,在進(jìn)行服務(wù)端開(kāi)發(fā)時(shí),必須通過(guò)ServerBootstrap引導(dǎo)類(lèi)的channel方法來(lái)...

    Flink_China 評(píng)論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列(一):ServerBootstrap 與 Bootstrap 初探

    摘要:而用于主線(xiàn)程池的屬性都定義在中本篇只是簡(jiǎn)單介紹了一下引導(dǎo)類(lèi)的配置屬性,下一篇我將詳細(xì)介紹服務(wù)端引導(dǎo)類(lèi)的過(guò)程分析。 從Java1.4開(kāi)始, Java引入了non-blocking IO,簡(jiǎn)稱(chēng)NIO。NIO與傳統(tǒng)socket最大的不同就是引入了Channel和多路復(fù)用selector的概念。傳統(tǒng)的socket是基于stream的,它是單向的,有InputStream表示read和Outpu...

    BakerJ 評(píng)論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列(五):深入淺出學(xué)NioEventLoopGroup

    摘要:接下來(lái)的兩篇文章,我將從源碼角度為大家深入淺出的剖析的線(xiàn)程模型工作機(jī)制。我們看一下的源碼通過(guò)的代碼發(fā)現(xiàn),實(shí)現(xiàn)了接口,其內(nèi)部會(huì)通過(guò)指定的默認(rèn)線(xiàn)程工廠(chǎng)來(lái)創(chuàng)建線(xiàn)程,并執(zhí)行相應(yīng)的任務(wù)。至此,初始化完成了。下一篇我們將詳細(xì)介紹,敬請(qǐng)期待。 我們都知道Netty的線(xiàn)程模型是基于React的線(xiàn)程模型,并且我們都知道Netty是一個(gè)高性能的NIO框架,那么其線(xiàn)程模型必定是它的重要貢獻(xiàn)之一。 在使用ne...

    MSchumi 評(píng)論0 收藏0
  • 【自己讀源碼Netty4.X系列(一) 啟動(dòng)類(lèi)概覽

    摘要:一些想法這個(gè)系列想開(kāi)很久了,自己使用也有一段時(shí)間了,利用也編寫(xiě)了一個(gè)簡(jiǎn)單的框架,并運(yùn)用到工作中了,感覺(jué)還不錯(cuò),趁著這段時(shí)間工作不是很忙,來(lái)分析一波源碼,提升下技術(shù)硬實(shí)力。 一些想法 這個(gè)系列想開(kāi)很久了,自己使用netty也有一段時(shí)間了,利用netty也編寫(xiě)了一個(gè)簡(jiǎn)單的框架,并運(yùn)用到工作中了,感覺(jué)還不錯(cuò),趁著這段時(shí)間工作不是很忙,來(lái)分析一波源碼,提升下技術(shù)硬實(shí)力。 結(jié)構(gòu) 這里先看下net...

    qingshanli1988 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<