Netty源碼分析-ChannelInitializer

ChannelInitializer是一個PPLine的初始化工具,可以往PPLine裏面設置Handler。

protected abstract void initChannel(C ch) throws Exception;

我們可以重寫此方法來完成初始化動作,往PPLine當中加入Handler。

.childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("initChannel:" + ch.localAddress());
                            ch.pipeline().addLast("log", new LoggingHandler(LogLevel.INFO));
        					ch.pipeline().addLast("DiscardHandler", new DiscardHandler());
                            ch.pipeline().addLast("hexEncoder2", new HexEncoder2());
        					ch.pipeline().addLast("hexEncoder1", new HexEncoder1());
                        }
                    });

 

在channel被註冊到EventLoop當中時,當前PPLine當中只有一個Handler,就是ChannelInitializer,它的channelRegistered會被調用。在它的initChannel子類回調中往PPLine中加入用戶自定義的Handler。

@Override
    @SuppressWarnings("unchecked")
    public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        //調用子類初始化方法,往PPline里加入Handler,該方法只會調用一次。
        //在調用之前PPLine當中只有一個handler。  PPline[---this----]
        //在調用之後PPLine當中加入了用戶自定義的Handler(ABCD)  PPline[---this---A---B---C---D---]
        if (initChannel(ctx)) {
            //重新調用channelRegistered防止事件丟失。
            ctx.pipeline().fireChannelRegistered();

            //移除當前Handler  移除後變爲PPline[---A---B---C---D---]
            removeState(ctx);
        } else {
            //向下傳遞事件
            ctx.fireChannelRegistered();
        }
    }

子類回到函數,初始化PPLine,成功返回true,同時移除自己。

 //子類回調成功返回true,否則返回false
    private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
    	//加入標記,保證方法只執行一次
        if (initMap.add(ctx)) { // Guard against re-entrance.
            try {
            	//子類回調函數
                initChannel((C) ctx.channel());
            } catch (Throwable cause) {
                // Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
                // We do so to prevent multiple calls to initChannel(...).
                exceptionCaught(ctx, cause);
            } finally {
            	//移除當前Handler
                ChannelPipeline pipeline = ctx.pipeline();
                if (pipeline.context(this) != null) {
                    pipeline.remove(this);
                }
            }
            return true;
        }
        return false;
    }

移除標記位。

private void removeState(final ChannelHandlerContext ctx) {
        //判斷當前ctx是否從PPLine當中移除
        if (ctx.isRemoved()) {
        	//移除執行清空標記位
            initMap.remove(ctx);
        } else {
            // The context is not removed yet which is most likely the case because a custom EventExecutor is used.
            // Let's schedule it on the EventExecutor to give it some more time to be completed in case it is offloaded.
            //否則加入EventLoop事件隊列,下一輪移除。
            ctx.executor().execute(new Runnable() {
                @Override
                public void run() {
                    initMap.remove(ctx);
                }
            });
        }
    }

 

    /**
     * {@inheritDoc} If override this method ensure you call super!
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    	//判斷channel是否已經註冊
        if (ctx.channel().isRegistered()) {
            // This should always be true with our current DefaultChannelPipeline implementation.
            // The good thing about calling initChannel(...) in handlerAdded(...) is that there will be no ordering
            // surprises if a ChannelInitializer will add another ChannelInitializer. This is as all handlers
            // will be added in the expected order.
            //調用子類
            if (initChannel(ctx)) {

                // We are done with init the Channel, removing the initializer now.
                removeState(ctx);
            }
        }
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章