Netty原理與基礎(二)

5.Handler業務處理器

在Reactor反應器經典模型中,反應器查詢到IO事件後,分發到Handler業務處理器,由Handler完成IO操作和業務處理。整個的IO處理操作環節包括:從通道讀數據包、數據包解碼、業務處理、目標數據編碼、把數據包寫到通道,然後由通道發送到對端


用戶程序主要在Handler業務處理器中,Handler涉及的環節爲:數據包解碼、業務處理、目標數據編碼、把數據包寫到通道中。

從應用程序開發人員的角度來看,有入站和出站兩種類型操作。
· 入站處理,觸發的方向爲:自底向上,Netty的內部(如通道)到ChannelInboundHandler入站處理器。
· 出站處理,觸發的方向爲:自頂向下,從ChannelOutboundHandler出站處理器到Netty的內部(如通道)。

  • ChannelInboundHandler通道入站處理器


  • ChannelOutboundHandler通道出站處理器


5.1ChannelInitializer通道初始化處理器

通道和Handler業務處理器的關係是:一條Netty的通道擁有一條Handler業務處理器流水線,負責裝配自己的Handler業務處理器
如果向流水線中裝配業務處理器呢?這就得藉助通道的初始化類——ChannelInitializer。

  • initChannel()方法是ChannelInitializer定義的一個抽象方法,這個抽象方法需要開發人員自己實現。在父通道調用initChannel()方法時,會將新接收的通道作爲參數,傳遞給initChannel()方法。initChannel()方法內部大致的業務代碼是:拿到新連接通道作爲實際參數,往它的流水線中裝配Handler業務處理器。

5.2ChannelInboundHandler的生命週期

ChannelInboundHandler的生命週期分2類:

  • 生命週期方法
    (1)handlerAdded() :當業務處理器被加入到流水線後,此方法被回調。也就是在完成ch.pipeline().addLast(handler)語句之後,會回調handlerAdded()。
    (2)channelRegistered():當通道成功綁定一個NioEventLoop線程後,會通過流水線回調所有業務處理器的channelRegistered()方法。(3)channelActive():當通道激活成功後,會通過流水線回調所有業務處理器的channelActive()方法。通道激活成功指的是,所有的業務處理器添加、註冊的異步任務完成,並且NioEventLoop線程綁定的異步任務完成。(4)channelInactive():當通道的底層連接已經不是ESTABLISH狀態,或者底層連接已經關閉時,會首先回調所有業務處理器的channelInactive()方法。
    (5)channelUnregistered():通道和NioEventLoop線程解除綁定,移除掉對這條通道的事件處理之後,回調所有業務處理器的channelUnregistered ()方法。
    (6)handlerRemoved():最後,Netty會移除掉通道上所有的業務處理器,並且回調所有的業務處理器的handlerRemoved()方法。
    -入棧回調方法
    (1)channelRead():有數據包入站,通道可讀。流水線會啓動入站處理流程,從前向後,入站處理器的channelRead()方法會被依次回調到。
    (2)channelReadComplete():流水線完成入站處理後,會從前向後,依次回調每個入站處理器的channelReadComplete()方法,表示數據讀取完畢。

5.3代碼示例

public class InHandlerDemo extends ChannelInboundHandlerAdapter {
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Logger.info("被調用:handlerAdded()");
        super.handlerAdded(ctx);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        Logger.info("被調用:channelRegistered()");
        super.channelRegistered(ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Logger.info("被調用:channelActive()");
        super.channelActive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Logger.info("被調用:channelRead()");
        super.channelRead(ctx, msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        Logger.info("被調用:channelReadComplete()");
        super.channelReadComplete(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Logger.info("被調用:channelInactive()");
        super.channelInactive(ctx);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        Logger.info("被調用: channelUnregistered()");
        super.channelUnregistered(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Logger.info("被調用:handlerRemoved()");
        super.handlerRemoved(ctx);
    }
}

測試類

public class InHandlerDemoTester {
    @Test
    public void testInHandlerLifeCircle() {
        final InHandlerDemo inHandler = new InHandlerDemo();
        //初始化處理器
        ChannelInitializer i = new ChannelInitializer<EmbeddedChannel>() {
            @Override
            protected void initChannel(EmbeddedChannel ch) {
                ch.pipeline().addLast(inHandler);
            }
        };
        //創建嵌入式通道
        EmbeddedChannel channel = new EmbeddedChannel(i);
        ByteBuf buf = Unpooled.buffer();
        buf.writeInt(1);
        //模擬入站,寫一個入站包
        channel.writeInbound(buf);
        channel.flush();
        //模擬入站,再寫一個入站包
        channel.writeInbound(buf);
        channel.flush();
        //通道關閉
        channel.close();
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

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