天天看點

Netty學習6-源碼跟蹤ChannelPipeline和ChanelHandler工作原理1 概述2 server啟動3 client啟動4 client發送資訊5 簡要流程圖

netty中的channelpipeline類似于servlet,chanelhandler類似于filter。這類攔截器就是職責鍊設計模式,主要是事件攔截和使用者業務邏輯定制。示範代碼采用的是netty

3.10.5版本。調試步驟和示例代碼如下:

步驟1 下載下傳完成後導入為maven項目。

步驟2 需要測試的項目在configure build path時不要直接導入netty3的jar包,直接導入project項目。

步驟3 對關注的方法打斷點。

步驟4 跟蹤調用鍊。

handler是通過pipeline的addlast方法添加的,那首先将斷點定位該處。

在示例代碼中,debug方式運作server,耐心一步步跟着斷點往下走,注意檢視調用鍊。

a defaultchannelpileline@addlast

Netty學習6-源碼跟蹤ChannelPipeline和ChanelHandler工作原理1 概述2 server啟動3 client啟動4 client發送資訊5 簡要流程圖

斷點如約而至,從調用鍊中可看出入口是serverbootstrap的bindasync方法。

bosspipeline.addlast("binder", binder)指派了一個名為binder的處理器。繼續跟進addlast方法。

b defaultchannelpileline@init

name2ctx是儲存handlercontext的集合對象,此時是空的。斷點走進init方法,逐行分析方法内的這幾行代碼。

Netty學習6-源碼跟蹤ChannelPipeline和ChanelHandler工作原理1 概述2 server啟動3 client啟動4 client發送資訊5 簡要流程圖

第1行 聲明了defaultchannelhandlercontext對象,傳入name值是binder,handler是名為binder的處理器,這兩個值初始化的地方就在上文看到的調用鍊的bootstrap的bind方法中。先看defaultchannelhandlercontext該類使用到的屬性。很明顯這是連結清單的資料結構,prev指向上個對象,next指向下個對象。

第2行 binder并不是lifecycleawarechannelhandler類型,直接return掉。

第3行 将連結清單中的第1個head和最後一個tail都指派給了第1行中聲明的對象。

第4行 清除map對象中的值。

第5行 将第1行聲明的對象指派給map集合。

第6行 binder并不是lifecycleawarechannelhandler類型,直接return掉。第一個需要關注的斷點到此結束。

利用telnet啟動一個用戶端。telnet 127.0.0.1 10101。這次設定斷點在位置server類中的channels.pipeline()位置

a channels.pipeline()

Netty學習6-源碼跟蹤ChannelPipeline和ChanelHandler工作原理1 概述2 server啟動3 client啟動4 client發送資訊5 簡要流程圖

新生成了一個channelpipeline對象。從調用鍊可看出【1】boss線程池負責接收連接配接。【2】上遊是nioserverboss@registeracceptedchannel。在建立連接配接時,該channelpipeline的所有handler将被設定完成。

b pipeline.addlast(decoder)

添加stringdecoder這個處理器,流程和4.2中的所有步驟一緻,都是走init方法,同樣在callbeforeadd和callafteradd中return了。唯一不同的是name叫做decoder。

c pipeline.addlast(xyhellohandler)

name2ctx不再empty,進入else分支。

Netty學習6-源碼跟蹤ChannelPipeline和ChanelHandler工作原理1 概述2 server啟動3 client啟動4 client發送資訊5 簡要流程圖

checkduplicatename檢查是否有重名,有重名則直接抛出異常。

oldtail表示原來尾對象,新申明的xyhellohandler将被作為新尾對象。再把原oldtail的next指向xyhellohandler,再放入name2ctx集合。

d abstractnioselector@select

繼續跟着斷點走,會走到abstractnioselector的select方法,select會阻塞,等待下一次事件。

在telnet視窗按下ctrl+] 會進入telnet的發送視窗。現在關注以下2個方法的調用鍊,stringdecoder@decode、hellohandler@messagereceived斷點到這兩個方法。

a stringdecoder@decode

Netty學習6-源碼跟蹤ChannelPipeline和ChanelHandler工作原理1 概述2 server啟動3 client啟動4 client發送資訊5 簡要流程圖

從nioworker的read方法開始,執行到defaultchannelpipeline的sendupstream,首先執行該pipeline的head的handler,而這個管道的head handler是stringdecoder。

進入sendupstream(head, e)方法,會先調用stringdecoder父類onetoonedecoder的handleupstream()方法。

父類方法調用子類的decode方法,如此這般stringdecoder的decode方法就被調用到了。

b hellohandler@messagereceived

注意上述方法中還調用firemessagereceived(ctx, decodedmessage, e.getremoteaddress())。一層一層進入該方法,最終會執行到defaultchannelpipeline的内部類defaultchannelhandlercontext的sendupstream方法

next相當于擷取了head的下一個handler對象即hellohanlder。當然hellohandler中也有所謂的鍊式調用,繼續調用firemessagereceived,若它的next還指向其他handler則會繼續調用。

Netty學習6-源碼跟蹤ChannelPipeline和ChanelHandler工作原理1 概述2 server啟動3 client啟動4 client發送資訊5 簡要流程圖

流程圖參考位址 http://blog.csdn.net/zxhoo/article/details/17264263