中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

netty中pipeline的handler怎么添加刪除

發布時間:2023-04-25 17:04:07 來源:億速云 閱讀:137 作者:iii 欄目:開發技術

今天小編給大家分享一下netty中pipeline的handler怎么添加刪除的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    添加

    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拿到當前的pipline, 拿到pipeline之后再為其添加handler, 因為channel初始化默認創建的是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只有一個

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

    分為四個步驟:

    • 重復添加驗證

    • 創建一個HandlerContext并添加到列表

    • 添加context

    • 回調添加事件

    checkMultiplicity(handler)重復添加驗證

    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.");
            }
            //滿足條件設置為true, 代表已添加
            h.added = true;
        }
    }
    • 首先判斷是不是ChannelHandlerAdapter類型, 因為我們自定義的handler通常會直接或者間接的繼承該接口, 所以這里為true拿到handler之后轉換成ChannelHandlerAdapter類型。

    • 然后進行條件判斷 if (!h.isSharable() && h.added) 代表如果不是共享的handler, 并且是未添加狀態, 則拋出異常。

    isSharable()
    public boolean isSharable() { 
        Class<?> clazz = getClass();
        Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
        Boolean sharable = cache.get(clazz);
        if (sharable == null) { 
            //如果這個類注解了Sharable.class, 說明這個類會被多個channel共享
            sharable = clazz.isAnnotationPresent(Sharable.class);
            cache.put(clazz, sharable);
        }
        return sharable;
    }
    • 首先拿到當前handlerclass對象。

    • 然后再從netty自定義的一個ThreadLocalMap對象中獲取一個盛放handlerclass對象的map, 并獲取其value

    • 如果value值為空, 則會判斷是否被Sharable注解, 并將自身handlerclass對象和判斷結果存入map對象中, 最后返回判斷結果。

    • 這說明了被Sharable注解的handler是一個共享handler

    • 從這個邏輯我們可以判斷, 共享對象是可以重復添加的。

    回到DefaultChannelPipeline.addLast,如果是共享對象或者沒有被添加, 則將ChannelHandlerAdapteradded設置為true, 代表已添加分析完了重復添加驗證, 回到addLast方法中, 我們看第二步, 創建一個HandlerContext并添加到列表

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

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

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

    filterName(name, handler)

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

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

    因為我們添加handler時候, 不一定會給handler命名, 所以這一步name有可能是null, 如果是null, 則創建一個默認的名字, 這里創建名字的方法就不分析了

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

    繼續跟進分析context0(name)方法

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

    這里的邏輯就是將pipeline中, 從head節點往下遍歷HandlerContext, 一直遍歷到tail, 如果發現名字相同則會認為重復并返回HandlerContext對象。

    繼續跟到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);
    }

    可以看到創建了一個DefaultChannelHandlerContext對象, 構造方法的參數中, 第一個this代表當前的pipeline對象, groupnull, 所以childExecutor(group)也會返回null, namehandler的名字, handler為新添加的handler對象

    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;
    }
    • 首先調用了父類的構造方法, 之后將handler賦值為自身handler的成員變量, HandlerConexthandler關系在此也展現了出來, 是一種組合關系

    • 父類的構造方法, 有這么兩個參數:isInbound(handler), isOutbound(handler), 這兩個參數意思是判斷需要添加的handlerinboundHandler還是outBoundHandler

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

    這里通過是否實現ChannelInboundHandler接口來判斷是否為inboundhandler

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

    通過判斷是否實現ChannelOutboundHandler接口判斷是否為outboundhandler

    在跟到其父類AbstractChannelHandlerContext的構造方法中
    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節點和head節點創建的時候也執行到了這里,初始化了name, pipeline, 以及標識添加的handlerinboundhanlder還是outboundhandler

    回到DefaultChannelPipeline.addLast,分析完了創建HandlerContext的相關邏輯, 我們繼續跟第三步, 添加HandlerContext

    addLast0(newCtx)

    private void addLast0(AbstractChannelHandlerContext newCtx) {
        //拿到tail節點的前置節點
        AbstractChannelHandlerContext prev = tail.prev;
        //當前節點的前置節點賦值為tail節點的前置節點
        newCtx.prev = prev;
        //當前節點的下一個節點賦值為tail節點
        newCtx.next = tail;
        //tail前置節點的下一個節點賦值為當前節點
        prev.next = newCtx;
        //tail節點的前一個節點賦值為當前節點
        tail.prev = newCtx;
    }

    做了一個指針的指向操作, 將新添加的handlerConext放在tail節點之前, 之前tail節點的上一個節點之后, 如果是第一次添加handler, 那么添加后的結構入下圖所示

    netty中pipeline的handler怎么添加刪除

    添加完handler之后, 這里會判斷當前channel是否已經注冊, 這部分邏輯之后再進行分析,先接著繼續執行。

    之后會判斷當前線程線程是否為eventLoop線程, 如果不是eventLoop線程, 就將添加回調事件封裝成task交給eventLoop線程執行, 否則, 直接執行添加回調事件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是我們新創建的HandlerContext, 通過handler()方法拿到綁定的handler, 也就是新添加的handler, 然后執行handlerAdded(ctx)方法, 如果我們沒有重寫這個方法, 則會執行父類的該方法。

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

    沒做任何操作, 也就是如果我們沒有重寫該方法時, 如果添加handler之后將不會做任何操作, 這里如果我們需要做一些業務邏輯, 可以通過重寫該方法進行實現

    刪除

    刪除的邏輯和添加的邏輯相同,區別刪除是將pipeline的雙向鏈表的節點去掉。這里就不詳細的分析。

    以上就是“netty中pipeline的handler怎么添加刪除”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    黎城县| 保定市| 常德市| 三都| 平昌县| 梧州市| 博爱县| 浙江省| 山阴县| 福贡县| 德兴市| 勐海县| 石台县| 伽师县| 义乌市| 舞阳县| 芒康县| 甘德县| 平遥县| 三河市| 漳平市| 高要市| 华容县| 遵义县| 屏山县| 墨竹工卡县| 应用必备| 当涂县| 都昌县| 宁津县| 长泰县| 运城市| 那曲县| 汝南县| 通州市| 阜康市| 龙陵县| 交城县| 广东省| 新巴尔虎左旗| 阿克|