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);
            }
        }
    }

 

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