第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁 慕課教程 Netty 教程 Netty 教程 Netty ChannelHandler生命周期

Netty ChannelHandler 生命周期

1. 前言

本節(jié)內(nèi)容,我們主要講解 ChannelHandler 在執(zhí)行過程中的生命周期是什么樣的?需要執(zhí)行哪些核心的生命周期方法以及順序?

了解生命周期的核心目的是,可以在合適的生命周期方法擴(kuò)展自己的業(yè)務(wù)功能。

2. UML 關(guān)系

首先,我們先來了解以下 ChannelHandler 的類依賴關(guān)系圖,具體如下所示:
圖片描述

通過上面的類結(jié)構(gòu)圖,我們總結(jié)一下規(guī)律:

  1. ChannelHandler 有兩個(gè)子接口,分別是 ChannelInboundHandlerChannelOutboundHandler,其實(shí)從字面意思就能知道,它們分別是入站和出站的接口類。
  2. 如果我們自定義的業(yè)務(wù) Handler 直接實(shí)現(xiàn) ChannelInboundHandler 或者 ChannelOutboundHandler,那么我們需要實(shí)現(xiàn)的接口非常的多,增加了開發(fā)的難度。Netty 已經(jīng)幫我們封裝好了兩個(gè)實(shí)現(xiàn)類,分別是 ChannelInboundHandlerAdapter 和 ChannelOutboundHandlerAdapter,這樣可以大大簡化了開發(fā)工作。

3. 核心生命周期方法

方法 描述
handlerAdded Handler 被加入 Pipeline 時(shí)觸發(fā)(僅僅觸發(fā)一次)
channelRegistered channelRegistered 注冊成功時(shí)觸發(fā)
channelActive channel 連接就緒時(shí)觸發(fā)
channelRead channel 有數(shù)據(jù)可讀時(shí)觸發(fā)
channelReadComplete channel 有數(shù)據(jù)可讀,并且讀完時(shí)觸發(fā)
channelInactive channel 斷開時(shí)觸發(fā)
channelUnregistered channel 取消注冊時(shí)觸發(fā)
handlerRemoved handler 被從 Pipeline 移除時(shí)觸發(fā)

問題 1:channelRegistered 注冊指的是什么呢?

Channel 在創(chuàng)建時(shí),需要綁定 ChannelPipeline 和 EventLoop 等操作,完成這些操作時(shí)會觸發(fā) channelRegistered () 方法。

問題 2:channelRead 和 channelReadComplete 的區(qū)別?

當(dāng) Channel 有數(shù)據(jù)可讀時(shí),會觸發(fā) channelRead 事件,eventLoop 被喚醒并且調(diào)用 channelRead () 處理數(shù)據(jù);eventLoop 喚醒后讀取數(shù)據(jù)包裝成 msg,然后將 msg 作為參數(shù)調(diào)用 channelRead (),期間做了個(gè)判斷,讀取到 0 字節(jié)或者讀取到的字節(jié)數(shù)小于 buffer 的容量,滿足以上條件就會調(diào)用 channelReadComplete ()。

4. 生命周期執(zhí)行流程

ChannelHandler 的一些特殊回調(diào)方法,這些回調(diào)方法的執(zhí)行是有順序的,而這個(gè)執(zhí)行順序可以稱為 ChannelHandler 的生命周期。

4.1 客戶端發(fā)送一次請求

public class InboundHandler1 extends ChannelInboundHandlerAdapter {
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handlerAdded");
        super.handlerAdded(ctx);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelRegistered");
        super.channelRegistered(ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelActive");
        super.channelActive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("channelRead");
        super.channelRead(ctx, msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelReadComplete");
        super.channelReadComplete(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelInactive");
        super.channelInactive(ctx);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelUnregistered");
        super.channelUnregistered(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handlerRemoved");
        super.handlerRemoved(ctx);
    }
}

執(zhí)行結(jié)果:

handlerAdded
channelRegistered
channelActive
channelRead
channelReadComplete

4.2 客戶端發(fā)送多次請求

客戶端每隔 5 秒鐘發(fā)送一次消息給服務(wù)端,查看效果如何?

實(shí)例:

final ChannelFuture channelFuture=bootstrap.connect("127.0.0.1",80).sync();
channelFuture.addListener(new ChannelFutureListener() {
    public void operationComplete(ChannelFuture future) throws Exception {
        if(future.isDone()){
            if(future.isSuccess()){
                
                //1秒鐘之后,每隔5描述發(fā)送一次消息
                channelFuture.channel().eventLoop().scheduleWithFixedDelay(new Runnable() {
                    public void run() {
                        channelFuture.channel().writeAndFlush("hello world");
                    }
                },1,5, TimeUnit.SECONDS);

            }else if(future.isCancelled()){
                System.out.println("連接被取消");
            }else if(future.cause()!=null){
                System.out.println("連接出錯(cuò):");
            }
        }
    }
});

執(zhí)行結(jié)果:

handlerAdded
channelRegistered
channelActive
channelRead
channelReadComplete
    
channelRead
channelReadComplete
    
channelRead
channelReadComplete

通過執(zhí)行結(jié)果我們發(fā)現(xiàn),第一次的時(shí)候執(zhí)行 handlerAdded ()、channelRegistered ()、channelActive (),后面就不會被執(zhí)行了。

客戶端的每次請求時(shí),都會觸發(fā) channelRead () 和 channelReadComplete () 兩個(gè)核心方法。

4.3 手工關(guān)閉通道

疑問:channelInactive、channelUnregistered、handlerRemoved 什么時(shí)候會被執(zhí)行呢?

實(shí)例:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    System.out.println("channelRead");
    //手工關(guān)閉通道
    ctx.channel().close();
}

執(zhí)行結(jié)果:

handlerAdded
channelRegistered
channelActive
channelRead
channelReadComplete
channelInactive
channelUnregistered
handlerRemoved

總結(jié),人為的關(guān)閉通道或者其他因素(比如:網(wǎng)絡(luò)故障等),則會觸發(fā) channelInactive、channelUnregistered、handlerRemoved 的執(zhí)行。

4.4 生命周期總結(jié)

我們來逐個(gè)總結(jié)一下每個(gè)回調(diào)方法的含義

  1. handlerAdded () :當(dāng)檢測到新連接之后,調(diào)用 ch.pipeline().addLast(new LifeCycleHandler()); 之后的回調(diào),表示在當(dāng)前的 channel 中,已經(jīng)成功添加了一個(gè) handler 到雙向鏈表。
  2. channelRegistered ():這個(gè)回調(diào)方法,表示當(dāng)前的 channel 的所有的邏輯處理已經(jīng)和某個(gè) NIO 線程建立了綁定關(guān)系,從線程池里面去抓一個(gè)線程綁定在這個(gè) channel 上,這里的 NIO 線程通常指的是 NioEventLoop。
  3. channelActive ():當(dāng) channel 的所有的業(yè)務(wù)邏輯鏈準(zhǔn)備完畢,channel 的 pipeline 中已經(jīng)添加完所有的 handler 以及綁定好一個(gè) NIO 線程之后,這條連接算是真正激活了,接下來就會回調(diào)到此方法。
  4. channelRead ():客戶端向服務(wù)端發(fā)來數(shù)據(jù),每次都會回調(diào)此方法,表示有數(shù)據(jù)可讀。
  5. channelReadComplete ():服務(wù)端每次讀完一次完整的數(shù)據(jù)之后,回調(diào)該方法,表示數(shù)據(jù)讀取完畢。
  6. channelInactive (): 表面這條連接已經(jīng)被關(guān)閉了,這條連接在 TCP 層面已經(jīng)不再是 ESTABLISH 狀態(tài)了。
  7. channelUnregistered (): 既然連接已經(jīng)被關(guān)閉,那么與這條連接綁定的線程就不需要對這條連接負(fù)責(zé)了,這個(gè)回調(diào)就表明與這條連接對應(yīng)的 NIO 線程移除掉對這條連接的處理。
  8. handlerRemoved ():給這條連接上添加的所有的業(yè)務(wù)邏輯處理器都給移除掉。

ChannelHandler 回調(diào)方法的執(zhí)行順序?yàn)?/p>

  1. 連接請求,handlerAdded () -> channelRegistered () -> channelActive () -> channelRead () -> channelReadComplete ();
  2. 數(shù)據(jù)請求,channelRead () -> channelReadComplete ();
  3. 通道被關(guān)閉,channelInactive () -> channelUnregistered () -> handlerRemoved ()。

圖片描述

5. 小結(jié)

本節(jié)內(nèi)容主要講解 ChannelHandler 的生命周期方法的執(zhí)行順序及觸發(fā)機(jī)制,目的是了解每個(gè)方法的觸發(fā)時(shí)間點(diǎn),有助于業(yè)務(wù)點(diǎn)的擴(kuò)展。核心掌握以下知識點(diǎn):

  1. 核心的生命周期方法有哪些,它們的觸發(fā)時(shí)間點(diǎn)是什么;
  2. channelRegistered 需要清楚,這個(gè)不容易理解;
  3. channelRead 和 channelReadComplete 的區(qū)別,需要清楚;
  4. 通過三種 Demo 來說明了不同的生命周期方法的執(zhí)行次數(shù),有的是只執(zhí)行一次,有的是每次都會執(zhí)行。