《跟閃電俠學(xué)Netty》閱讀筆記 - ChannelHandler 生命周期
Part1引言
本文主要介紹ChannelHandler當(dāng)中的ChannelInboundHandler。
Part2思維導(dǎo)圖
https://www.mubu.com/doc/1lK922R14Bl

Part3LifeCycleTestHandler 案例
首先來(lái)看一下案例,LifeCycleTestHandlerTest 利用適配器 ChannelInboundHandlerAdapter 重寫(xiě),重寫(xiě)相關(guān)方法。
public void handlerAdded(ChannelHandlerContext ctx) throws Exception
public void channelRegistered(ChannelHandlerContext ctx) throws Exception
public void channelActive(ChannelHandlerContext ctx) throws Exception
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception
public void channelInactive(ChannelHandlerContext ctx) throws Exception
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception
/**
?*?測(cè)試netty?channelHandler?的生命周期
?*
?*?對(duì)應(yīng)的是?ChannelInboundHandlerAdapter
?*/
4j
public?class?LifeCycleTestHandlerTest?extends?ChannelInboundHandlerAdapter?{
????public?static?void?main(String[]?args)?{
????????ServerBootstrap?serverBootstrap?=?new?ServerBootstrap();
????????NioEventLoopGroup?boss?=?new?NioEventLoopGroup();
????????NioEventLoopGroup?worker?=?new?NioEventLoopGroup();
????????serverBootstrap
????????????????.group(boss,?worker)
????????????????.channel(NioServerSocketChannel.class)
????????????????.childHandler(new?ChannelInitializer<NioSocketChannel>()?{
????????????????????
????????????????????protected?void?initChannel(NioSocketChannel?ch)?throws?Exception?{
????????????????????????ch.pipeline().addLast(new?StringDecoder());
????????????????????????ch.pipeline().addLast(new?LifeCycleTestHandlerTest());
????????????????????}
????????????????})
????????????????.bind(8001);
????}
????
????public?void?handlerAdded(ChannelHandlerContext?ctx)?throws?Exception?{
????????log.info("邏輯處理器被添加?handlerAdded()?");
????????super.handlerAdded(ctx);
????}
????
????public?void?channelRegistered(ChannelHandlerContext?ctx)?throws?Exception?{
????????log.info("channel?綁定到線程?(NioEventLoop):channelRegistered()?");
????????super.channelRegistered(ctx);
????}
????
????public?void?channelActive(ChannelHandlerContext?ctx)?throws?Exception?{
????????log.info("channel?準(zhǔn)備就緒?channelActive()");
????????super.channelActive(ctx);
????}
????
????public?void?channelReadComplete(ChannelHandlerContext?ctx)?throws?Exception?{
????????log.info("channel?某次數(shù)據(jù)讀寫(xiě)完成?channelReadComplete()?");
????????super.channelReadComplete(ctx);
????}
????
????public?void?channelRead(ChannelHandlerContext?ctx,?Object?msg)?throws?Exception?{
????????log.info("channel?有數(shù)據(jù)可讀?channelRead()?");
????????super.channelRead(ctx,?msg);
????}
????
????public?void?channelInactive(ChannelHandlerContext?ctx)?throws?Exception?{
????????log.info("channel?被關(guān)閉?channelInactive()");
????????super.channelInactive(ctx);
????}
????
????public?void?channelUnregistered(ChannelHandlerContext?ctx)?throws?Exception?{
????????log.info("channel取消線程?(NioEventLoop)?的綁定:channelUnregistered()?");
????????super.channelUnregistered(ctx);
????}
????
????public?void?handlerRemoved(ChannelHandlerContext?ctx)?throws?Exception?{
????????log.info("邏輯處理器被刪除?handlerRemoved()?");
????????super.handlerRemoved(ctx);
????}
}
如果啟動(dòng)Client客戶端并且進(jìn)行連接,ChannelHanlder 的回調(diào)方法執(zhí)行順序如下:
handlerAdded()
channelRegistered()
channelActive()
channelRead()
channelReadComplete()
1Channel連接方法回調(diào)
根據(jù)上面的執(zhí)行順序,這里補(bǔ)充介紹回調(diào)方法的含義。
邏輯處理器被添加:
handlerAdded() ?
檢測(cè)到新連接,調(diào)用
ch.pipleLine(new LifeCycleTestHandlerTest())
之后的回調(diào),表示當(dāng)前的Channel成功綁定一個(gè)邏輯處理器。channel 綁定到線程 (NioEventLoop):
channelRegistered() ?
表示當(dāng)前Channel所有邏輯處理器和某個(gè)線程模型的線程綁定完成,比如綁定到NIO模型的NioEventLoop。此時(shí)會(huì)創(chuàng)建線程處理連接的讀寫(xiě),具體使用了JDK的線程池實(shí)現(xiàn),通過(guò)線程池抓一個(gè)線程方式綁定。
channel 準(zhǔn)備就緒:
channelActive()
觸發(fā)條件是所有的業(yè)務(wù)邏輯準(zhǔn)備完成,也就是pipeline添加了所有的Handler ,以及綁定好一個(gè)NIO的線程之后,相當(dāng)于是worker全部就位,就等boss一聲令下開(kāi)工。
channel 有數(shù)據(jù)可讀
channelRead()
客戶端每次發(fā)數(shù)據(jù)都會(huì)以此進(jìn)行回調(diào)。
channel 某次數(shù)據(jù)讀寫(xiě)完成
channelReadComplete()
服務(wù)端每次處理以此數(shù)據(jù)都回調(diào)此方法進(jìn)行回調(diào) 。
Part4Channel 關(guān)閉方法回調(diào)
channel 被關(guān)閉:
channelInactive()
TCP層已經(jīng)轉(zhuǎn)為非ESTABLISH模式。
channel取消線程 (NioEventLoop) 的綁定:
channelUnregistered()
與連接線程的綁定全部取消時(shí)候觸發(fā)。
邏輯處理器被刪除:
handlerRemoved()
移除連接對(duì)應(yīng)的所有業(yè)務(wù)邏輯處理器觸發(fā)。
Part5Channel連接和關(guān)閉回調(diào)流程圖

Part6ChannelHanlder用法舉例
2ChannelInitializer
入門(mén)程序當(dāng)中的 .childHandler(new ChannelInitializer<NioSocketChannel>()
定義了抽象initChannel方法,抽象方法需要自行實(shí)現(xiàn),通常是服務(wù)端啟動(dòng)流程的邏輯處理器中使用,添加Handler鏈到Pipeline。
handlerAdded()
方法和 channelRegistered()
方法都會(huì)嘗試調(diào)用 initChannel,initChannel被多次調(diào)用,利用putIfAbsent防止initChannel被多次調(diào)用。
if?(initMap.putIfAbsent(ctx,?Boolean.TRUE)?==?null)?{?//?Guard?against?re-entrance.??
思考:為什么既要防止被多次調(diào)用,Netty又要調(diào)用多次
initChannel
?
1. handlerAdded方法已經(jīng)通過(guò)Channel
進(jìn)行綁定。 2. 用戶自行覆蓋和重寫(xiě)ChannelInitializer
的handlerAdded
,導(dǎo)致Channel
不觸發(fā)綁定
3.channelRegisted()
中再觸發(fā)一次綁定,并且本身不允許被重寫(xiě)。public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
4. 引導(dǎo)實(shí)現(xiàn)者只關(guān)注重寫(xiě)handlerAdded之后的邏輯處理
3handlerAdded 與 channelInActive
主要用做資源釋放和申請(qǐng)。
4channelActive 和 ChannelInActive
應(yīng)用的場(chǎng)景如下:
TCP建立和連接抽象
實(shí)現(xiàn)統(tǒng)計(jì)單機(jī)的連接數(shù)量
其中channelActive被調(diào)用,對(duì)應(yīng)的每次調(diào)用連接+1
其中channelInActive被調(diào)用,對(duì)應(yīng)的每次調(diào)用連接-1
實(shí)現(xiàn)客戶端IP黑白名單的連接過(guò)濾
5channelRead()
這個(gè)方法和粘包和拆包問(wèn)題相關(guān),服務(wù)端根據(jù)自定義協(xié)議拆包,在這個(gè)方法中每次讀取一定數(shù)據(jù),都會(huì)累加到容器當(dāng)中。
6channelReadComplete
每次向客戶端寫(xiě)入數(shù)據(jù)都調(diào)用writeAndFlush
不是很高效, ?更好的實(shí)現(xiàn)是向客戶端寫(xiě)數(shù)據(jù)只write
,但是在ChannelReadComplete
里面一次 flush ,所以這個(gè)方法相當(dāng)于批量刷新機(jī)制,批量刷新追求更高性能。
Part7總結(jié)
本部分主要是介紹ChannelHandler的各種回調(diào),以及連接建立關(guān)閉,執(zhí)行回調(diào)是一個(gè)逆向過(guò)程。
每一種回調(diào)都有各自用法,但是部分回調(diào)界限比較模糊,更多需要在實(shí)踐中區(qū)分和使用。
Part8寫(xiě)到最后
生命周期和回調(diào)在Netty中非常直觀,本文更多是對(duì)于重要的方法進(jìn)行羅列。