最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

netty中pipeline的handler添加刪除分析

 更新時(shí)間:2023年04月25日 11:32:24   作者:寬仔的編程之路  
這篇文章主要為大家介紹了netty中pipeline的handler添加刪除分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

添加

ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workGroup)
        .channel(NioServerSocketChannel.class)
        .childHandler(new ChannelInitializer<SocketChannel>(){
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new MyServerHandler());
            }
        });
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();

分析pipeline.addLast(new MyServerHandler())中的addLast。

首先通過channel拿到當(dāng)前的pipline, 拿到pipeline之后再為其添加handler, 因?yàn)?code>channel初始化默認(rèn)創(chuàng)建的是DefualtChannelPipeline

DefaultChannelPipeline.addLast(ChannelHandler... handlers)

public final ChannelPipeline addLast(ChannelHandler... handlers) {
    return addLast(null, handlers);
}
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;
}

這里的handlers只有一個(gè)

public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
    final AbstractChannelHandlerContext newCtx;
    synchronized (this) {
        //判斷handler是否被重復(fù)添加(1)
        checkMultiplicity(handler);
        //創(chuàng)建一個(gè)HandlerContext并添加到列表(2)
        newCtx = newContext(group, filterName(name, handler), handler);
        //添加HandlerContext(3)
        addLast0(newCtx);
        //是否已注冊(cè)
        if (!registered) {
            newCtx.setAddPending();
            callHandlerCallbackLater(newCtx, true);
            return this;
        }
        EventExecutor executor = newCtx.executor();
        if (!executor.inEventLoop()) {
            newCtx.setAddPending();
            //回調(diào)用戶事件
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    callHandlerAdded0(newCtx);
                }
            });
            return this;
        }
    }
    //回調(diào)添加事件(4)
    callHandlerAdded0(newCtx);
    return this;
}

分為四個(gè)步驟:

  • 重復(fù)添加驗(yàn)證
  • 創(chuàng)建一個(gè)HandlerContext并添加到列表
  • 添加context
  • 回調(diào)添加事件

checkMultiplicity(handler)重復(fù)添加驗(yàn)證

private static void checkMultiplicity(ChannelHandler handler) {
    if (handler instanceof ChannelHandlerAdapter) {
        ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler; 
        if (!h.isSharable() && h.added) {
            throw new ChannelPipelineException(
                    h.getClass().getName() +
                    " is not a @Sharable handler, so can't be added or removed multiple times.");
        }
        //滿足條件設(shè)置為true, 代表已添加
        h.added = true;
    }
}
  • 首先判斷是不是ChannelHandlerAdapter類型, 因?yàn)槲覀冏远x的handler通常會(huì)直接或者間接的繼承該接口, 所以這里為true拿到handler之后轉(zhuǎn)換成ChannelHandlerAdapter類型。
  • 然后進(jìn)行條件判斷 if (!h.isSharable() && h.added) 代表如果不是共享的handler, 并且是未添加狀態(tài), 則拋出異常。

isSharable()

public boolean isSharable() { 
    Class<?> clazz = getClass();
    Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
    Boolean sharable = cache.get(clazz);
    if (sharable == null) { 
        //如果這個(gè)類注解了Sharable.class, 說明這個(gè)類會(huì)被多個(gè)channel共享
        sharable = clazz.isAnnotationPresent(Sharable.class);
        cache.put(clazz, sharable);
    }
    return sharable;
}
  • 首先拿到當(dāng)前handlerclass對(duì)象。
  • 然后再?gòu)?code>netty自定義的一個(gè)ThreadLocalMap對(duì)象中獲取一個(gè)盛放handlerclass對(duì)象的map, 并獲取其value。
  • 如果value值為空, 則會(huì)判斷是否被Sharable注解, 并將自身handlerclass對(duì)象和判斷結(jié)果存入map對(duì)象中, 最后返回判斷結(jié)果。
  • 這說明了被Sharable注解的handler是一個(gè)共享handler。
  • 從這個(gè)邏輯我們可以判斷, 共享對(duì)象是可以重復(fù)添加的。

回到DefaultChannelPipeline.addLast,如果是共享對(duì)象或者沒有被添加, 則將ChannelHandlerAdapteradded設(shè)置為true, 代表已添加分析完了重復(fù)添加驗(yàn)證, 回到addLast方法中, 我們看第二步, 創(chuàng)建一個(gè)HandlerContext并添加到列表

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

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

首先看filterName(name, handler)方法, 這個(gè)方法是判斷添加handler的name是否重復(fù)

filterName(name, handler)

首先看filterName(name, handler)方法, 這個(gè)方法是判斷添加handlername是否重復(fù)

private String filterName(String name, ChannelHandler handler) {
    if (name == null) {
        //沒有名字創(chuàng)建默認(rèn)名字
        return generateName(handler);
    }
    //檢查名字是否重復(fù)
    checkDuplicateName(name);
    return name;
}

因?yàn)槲覀兲砑?code>handler時(shí)候, 不一定會(huì)給handler命名, 所以這一步name有可能是null, 如果是null, 則創(chuàng)建一個(gè)默認(rèn)的名字, 這里創(chuàng)建名字的方法就不分析了

checkDuplicateName(name)

private void checkDuplicateName(String name) {
    //不為空
    if (context0(name) != null) {
        throw new IllegalArgumentException("Duplicate handler name: " + name);
    }
}

繼續(xù)跟進(jìn)分析context0(name)方法

context0(name)

private AbstractChannelHandlerContext context0(String name) {
    //遍歷pipeline
    AbstractChannelHandlerContext context = head.next;
    while (context != tail) {
        //發(fā)現(xiàn)name相同, 說明存在handler
        if (context.name().equals(name)) {
            //返回
            return context;
        }
        context = context.next;
    }
    return null;
}

這里的邏輯就是將pipeline中, 從head節(jié)點(diǎn)往下遍歷HandlerContext, 一直遍歷到tail, 如果發(fā)現(xiàn)名字相同則會(huì)認(rèn)為重復(fù)并返回HandlerContext對(duì)象。

繼續(xù)跟到newContext(group, filterName(name, handler), handler)方法中。

newContext(EventExecutorGroup group, String name, ChannelHandler handler)

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

可以看到創(chuàng)建了一個(gè)DefaultChannelHandlerContext對(duì)象, 構(gòu)造方法的參數(shù)中, 第一個(gè)this代表當(dāng)前的pipeline對(duì)象, groupnull, 所以childExecutor(group)也會(huì)返回null, namehandler的名字, handler為新添加的handler對(duì)象

new DefaultChannelHandlerContext(this, childExecutor(group), name, handler)

DefaultChannelHandlerContext(
        DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
    super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
    if (handler == null) {
        throw new NullPointerException("handler");
    }
    this.handler = handler;
}
  • 首先調(diào)用了父類的構(gòu)造方法, 之后將handler賦值為自身handler的成員變量, HandlerConexthandler關(guān)系在此也展現(xiàn)了出來, 是一種組合關(guān)系
  • 父類的構(gòu)造方法, 有這么兩個(gè)參數(shù):isInbound(handler), isOutbound(handler), 這兩個(gè)參數(shù)意思是判斷需要添加的handlerinboundHandler還是outBoundHandler

isInbound(handler)

private static boolean isInbound(ChannelHandler handler) {
    return handler instanceof ChannelInboundHandler;
}

這里通過是否實(shí)現(xiàn)ChannelInboundHandler接口來判斷是否為inboundhandler

isOutbound(handler)

private static boolean isOutbound(ChannelHandler handler) {
    return handler instanceof ChannelOutboundHandler;
}

通過判斷是否實(shí)現(xiàn)ChannelOutboundHandler接口判斷是否為outboundhandler

在跟到其父類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;
}

之前tail節(jié)點(diǎn)和head節(jié)點(diǎn)創(chuàng)建的時(shí)候也執(zhí)行到了這里,初始化了name, pipeline, 以及標(biāo)識(shí)添加的handlerinboundhanlder還是outboundhandler。

回到DefaultChannelPipeline.addLast,分析完了創(chuàng)建HandlerContext的相關(guān)邏輯, 我們繼續(xù)跟第三步, 添加HandlerContext

addLast0(newCtx)

private void addLast0(AbstractChannelHandlerContext newCtx) {
    //拿到tail節(jié)點(diǎn)的前置節(jié)點(diǎn)
    AbstractChannelHandlerContext prev = tail.prev;
    //當(dāng)前節(jié)點(diǎn)的前置節(jié)點(diǎn)賦值為tail節(jié)點(diǎn)的前置節(jié)點(diǎn)
    newCtx.prev = prev;
    //當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)賦值為tail節(jié)點(diǎn)
    newCtx.next = tail;
    //tail前置節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)賦值為當(dāng)前節(jié)點(diǎn)
    prev.next = newCtx;
    //tail節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)賦值為當(dāng)前節(jié)點(diǎn)
    tail.prev = newCtx;
}

做了一個(gè)指針的指向操作, 將新添加的handlerConext放在tail節(jié)點(diǎn)之前, 之前tail節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)之后, 如果是第一次添加handler, 那么添加后的結(jié)構(gòu)入下圖所示

添加完handler之后, 這里會(huì)判斷當(dāng)前channel是否已經(jīng)注冊(cè), 這部分邏輯之后再進(jìn)行分析,先接著繼續(xù)執(zhí)行。

之后會(huì)判斷當(dāng)前線程線程是否為eventLoop線程, 如果不是eventLoop線程, 就將添加回調(diào)事件封裝成task交給eventLoop線程執(zhí)行, 否則, 直接執(zhí)行添加回調(diào)事件callHandlerAdded0(newCtx)。

callHandlerAdded0(newCtx)

private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
    try {
        ctx.handler().handlerAdded(ctx);
        ctx.setAddComplete();
    } catch (Throwable t) {
        /**
 		* 省略
 		* */
    }
}

分析ctx.handler().handlerAdded(ctx),其中ctx是我們新創(chuàng)建的HandlerContext, 通過handler()方法拿到綁定的handler, 也就是新添加的handler, 然后執(zhí)行handlerAdded(ctx)方法, 如果我們沒有重寫這個(gè)方法, 則會(huì)執(zhí)行父類的該方法。

ChannelHandlerAdapter.(ChannelHandlerContext ctx)

public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    // NOOP
}

沒做任何操作, 也就是如果我們沒有重寫該方法時(shí), 如果添加handler之后將不會(huì)做任何操作, 這里如果我們需要做一些業(yè)務(wù)邏輯, 可以通過重寫該方法進(jìn)行實(shí)現(xiàn)

刪除

刪除的邏輯和添加的邏輯相同,區(qū)別刪除是將pipeline的雙向鏈表的節(jié)點(diǎn)去掉。這里就不詳細(xì)的分析。

以上就是netty中pipelinehandler添加刪除分析的詳細(xì)內(nèi)容,更多關(guān)于netty pipeline handler的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java使用Iterator迭代器遍歷集合數(shù)據(jù)的方法小結(jié)

    Java使用Iterator迭代器遍歷集合數(shù)據(jù)的方法小結(jié)

    這篇文章主要介紹了Java使用Iterator迭代器遍歷集合數(shù)據(jù)的方法,結(jié)合實(shí)例形式分析了java迭代器進(jìn)行集合數(shù)據(jù)遍歷的常見操作技巧,需要的朋友可以參考下
    2019-11-11
  • java二叉樹面試題詳解

    java二叉樹面試題詳解

    下面小編就為大家?guī)硪黄猨ava二叉樹的幾道面試題詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2021-07-07
  • java實(shí)現(xiàn)在pdf模板的指定位置插入圖片

    java實(shí)現(xiàn)在pdf模板的指定位置插入圖片

    這篇文章主要為大家詳細(xì)介紹了java如何實(shí)現(xiàn)在pdf模板的指定位置插入圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Java注釋和關(guān)鍵字實(shí)例詳解

    Java注釋和關(guān)鍵字實(shí)例詳解

    注釋是對(duì)程序語(yǔ)言的說明,有助于開發(fā)者和用戶之間的交流,方便理解程序,注釋不是編程語(yǔ)句,因此被編譯器忽略,下面這篇文章主要給大家介紹了關(guān)于Java注釋和關(guān)鍵字的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • SpringBoot整合Shiro實(shí)現(xiàn)登錄認(rèn)證的方法

    SpringBoot整合Shiro實(shí)現(xiàn)登錄認(rèn)證的方法

    這篇文章主要介紹了SpringBoot整合Shiro實(shí)現(xiàn)登錄認(rèn)證的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-02-02
  • Hibernate單表操作實(shí)例解析

    Hibernate單表操作實(shí)例解析

    這篇文章主要介紹了Hibernate單表操作實(shí)例解析,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • Springboot集成Mybatis-Flex的示例詳解

    Springboot集成Mybatis-Flex的示例詳解

    Mybatis-Flex 是一個(gè)優(yōu)雅的?Mybatis 增強(qiáng)框架,它非常輕量、同時(shí)擁有極高的性能與靈活性,本文主要介紹了Springboot集成Mybatis-Flex的示例詳解,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • java文件操作之java寫文件簡(jiǎn)單示例

    java文件操作之java寫文件簡(jiǎn)單示例

    這篇文章主要介紹了java文件操作中的java寫文件示例,需要的朋友可以參考下
    2014-03-03
  • java中的FileInputStream三種read()函數(shù)用法

    java中的FileInputStream三種read()函數(shù)用法

    這篇文章主要介紹了java中的FileInputStream三種read()函數(shù)用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • MyBatis如何調(diào)用存儲(chǔ)過程

    MyBatis如何調(diào)用存儲(chǔ)過程

    這篇文章主要介紹了MyBatis如何調(diào)用存儲(chǔ)過程問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05

最新評(píng)論

乐东| 鱼台县| 泉州市| 贵州省| 永春县| 澄江县| 弥勒县| 丹江口市| 华阴市| 苏尼特左旗| 崇文区| 漾濞| 林芝县| 胶南市| 平远县| 长春市| 易门县| 阜南县| 喜德县| 昌黎县| 承德县| 宜春市| 栾城县| 封丘县| 靖州| 金阳县| 饶阳县| 南乐县| 祁连县| 巫山县| 中宁县| 原阳县| 台湾省| 白山市| 东山县| 获嘉县| 始兴县| 韩城市| 玛多县| 哈巴河县| 辽宁省|