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
斷點如約而至,從調用鍊中可看出入口是serverbootstrap的bindasync方法。
bosspipeline.addlast("binder", binder)指派了一個名為binder的處理器。繼續跟進addlast方法。
b defaultchannelpileline@init
name2ctx是儲存handlercontext的集合對象,此時是空的。斷點走進init方法,逐行分析方法内的這幾行代碼。
第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()
新生成了一個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分支。
checkduplicatename檢查是否有重名,有重名則直接抛出異常。
oldtail表示原來尾對象,新申明的xyhellohandler将被作為新尾對象。再把原oldtail的next指向xyhellohandler,再放入name2ctx集合。
d abstractnioselector@select
繼續跟着斷點走,會走到abstractnioselector的select方法,select會阻塞,等待下一次事件。
在telnet視窗按下ctrl+] 會進入telnet的發送視窗。現在關注以下2個方法的調用鍊,stringdecoder@decode、hellohandler@messagereceived斷點到這兩個方法。
a stringdecoder@decode
從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則會繼續調用。
流程圖參考位址 http://blog.csdn.net/zxhoo/article/details/17264263