天天看點

Netty4 2_ChannelInitializer

在上一篇部落格中,我們看到例子中有一段代碼

try  
        {  
            // 一個伺服器助手類  
            ServerBootstrap b = new ServerBootstrap();  
            b.group(bossGroup, workerGroup)  
                    //用它來建立新accept的連接配接,用于構造serversocketchannel的工廠類  
                    .channel(NioServerSocketChannel.class)  
                    //在serverBootstrap内部用該handler去處理執行個體化的channel  
                    .childHandler(new ChannelInitializer<SocketChannel>()
                    {  
                         //當有新accept的時候,這個方法會調用  
                        @Override  
                        public void initChannel(SocketChannel ch) 
                                throws Exception  
                        {  
                            ch.pipeline().addLast(new DiscardServerHandler());  
                        }  
                    });  
  
            // 綁定并等待accept到來的連接配接  
            ChannelFuture f = b.bind(port).sync();  
  
              
            //關閉伺服器  
            f.channel().closeFuture().sync();  
        } finally  
        {  
            workerGroup.shutdownGracefully();  
            bossGroup.shutdownGracefully();  
        }  
    }  
           

其中加入ServerBootstrap中處理channel卻是一個ChannelInitializer ,這是怎麼回事呢,不是應該相應的ChannelHandler嗎?

我們來看一下Channelnitializer源代碼吧

public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializer.class);

    /**
     * 這個方法會在Channle被注冊時候調用,在方法傳回之後,這個執行個體會在Channel對應的ChannelPipeline中删除
     *
     * @param ch            the {@link Channel} which was registered.
     * @throws Exception    is thrown if an error occurs. In that case the {@link Channel} will be closed.
     */
    protected abstract void initChannel(C ch) throws Exception;

    @SuppressWarnings("unchecked")
    @Override
    public final void channelRegistered(ChannelHandlerContext ctx)
            throws Exception {
        boolean removed = false;
        boolean success = false;
        try {
            initChannel((C) ctx.channel());
            ctx.pipeline().remove(this);
            removed = true;
            ctx.fireChannelRegistered();
            success = true;
        } catch (Throwable t) {
            logger.warn("Failed to initialize a channel. Closing: " + ctx.channel(), t);
        } finally {
            if (!removed) {
                ctx.pipeline().remove(this);
            }
            if (!success) {
                ctx.close();
            }
        }
    }
}
           
Netty4 2_ChannelInitializer

從上面可以看出ChannelInitializer也是一個ChannelHandler,隻是ChannelInitializer的主要任務不是對IO進行處理,而更多的負責對注冊到EventGroup的Channel進行init處理,其中大多是進行加入Handler的處理,也就是上一部落格中我們所看到的加入了一個自定義ChannelHandler

那他是怎麼實作在ChannelInitializer中進行相應的channel的init的呢

他的調用過程這樣的

Netty4 2_ChannelInitializer

在這裡請先記得ChannelPipeline、ChannelHandlerContext以及ChannelHandler三者的關系(在以後還會介紹)

Netty4 2_ChannelInitializer

是以呢,上面的流程就是在Channel對應的ChannelPipeline中調用它的register方法,再使得channelContextPipeline調用它的相應的register方法,最後才是ChannelInitializer(它也是一個ChannelHandler)

上面流程中在DefaultChannelPipeline中

Netty4 2_ChannelInitializer

head是一個ChannelHandlerContext,而我們再看一下DefaultChannelHandlerContext

Netty4 2_ChannelInitializer

最後就是我們在上文中ChannelInitializer的代碼了

Netty4 2_ChannelInitializer

最後就是我們上一節課例子中的ChannelInitializer内部類在ChannelPipeline中加入新的ChannelContext(對應自定義的ChannelHandler)了

至此,你會發現ChannelHandler是怎麼加入在ChannelPipeline中,對Channel進行處理了

繼續閱讀