Netty in Action (十六) 第六章節 第二部分 ChannelHandlerContext和異常處理
6.3 Interface ChannelHandlerContext
一個ChannelHandlerContext代表了一個ChannelHandler和ChannelPipeline之間的關係,ChannelHandlerContext創建於ChannelHandler被載入到ChannelPipeline的時候,ChannelHandlerContext主要功能是管理在同一ChannelPipeline中各個ChannelHandler的互動
ChannelHandlerContext有很多方法,其中的一些方法也出現在Channel和ChannelPipeline中,但是相同的方法卻有一些不同的效果,如果你在Channel或者在ChannelPipeline例項中實現這些方法,它們會傳播到整個管道,同樣的方法如果被ChannelHandlerContext執行的時候,那麼它會在當前關聯的ChannelHandler中開始執行,然後只會傳播到管道中符合條件(符合方向的有興趣的)的下一個ChannelHandler處理
表6.10總結了ChannelHandlerContext的APIs
當你使用ChannelHandlerContext的時候,請牢記以下幾點原則:
1)與ChannelHandlerContext關聯的ChannelHandler是不會改變的,所以如果對其引用做一份快取是安全的
2)ChannelHandlerContext的方法與定義在其他class中的方法是不一樣的,它有著較短的生命週期,這個可以被用來儘可能的提高應用的效能
6.3.1 Using ChannelHandlerContext
在這個小節中,我們將討論如何使用ChannelHandlerContext,並且檢視由ChannelHandlerContext,Channel,ChannelPipeline提供的一些方法,圖6.4向你展示了它們三者之間的關係
在下面的程式碼清單中,你將從ChannelHandlerContext中獲取一個Channel的引用,通過呼叫Channel的write的方法寫在管道里會引起一個寫入流
下面的程式碼清單也展示了一個相似的例子,這次也是用ChannelPipeline寫入,我們可以從ChannelHandlerContext中獲取的ChannelPipeline引用
程式碼清單6.6和程式碼清單6.7是很相似的,都如圖6.5所示,你必須注意到通過Channel或者ChannelPipeline呼叫write方法都會使事件沿著管道傳播,這一點是很重要的,從一個Channel到下一個Channel的移動是由ChannelHandlerContext管控的
為什麼有時候我們需要在ChannelPipeline中的某些具體的地方開始傳播一個事件呢?
1)減少事件在那些對該事件不感興趣的處理器傳播的損耗
2)防止那些“感興趣”的處理器處理後產生不好的影響
為了從一個指定的ChannelHandler開始執行處理,你必須指定一個ChannelHandler處理器之前的那個ChannelHandlerContext,這個ChannelHandlerContext會呼叫與它關聯的那個ChannelHandler,這個ChannelHandler也就是我們指定的那個處理器
下面的程式碼清單和圖6.6說明了這個使用的方法
如圖6.6所示,資訊從圖中第二個ChannelHandler中開始在ChannelPipeline中傳播,跳過了前一個
我們剛才描述使用的是一個很常見的一種使用方式,呼叫一個特定的ChannelHandler例項是一個非常有用的操作方式
6.3.2 Advanced uses of ChannelHandler and ChannelHandlerContext
在我們之前看見的6.6清單所示,我們通過ChannelHandlerContext的pipeline方法獲取到一個ChannelPipeline的引用,這裡可以在執行的時候操作管道中的ChannelHandler,這裡可以在複雜的業務場景中用到,例如,你可以通過增加一個ChannelHandler到管道中來支援動態協議的改變
另一個使用的好處就是獲取一個ChannelHandlerContext的一個引用,這個引用的快取可以支援“延遲使用”,這樣可以發生在ChannelHandler之外甚至可以給不同的執行緒都執行,下面的程式碼清單展示了這種模式
因為一個ChannelHandler可以屬於多個ChannelPipeline,它也可以繫結多個ChannelHandlerContext例項,如果一個ChannelHandler想要有這樣的功能,就必須以@Sharable註解註釋這個ChannelHandler,否則,嘗試將其加入到不止一個ChannelPipeline中去的時候,會報出異常,很明顯,使用這樣的支援多執行緒的channel你必須保證該類是執行緒安全的,無狀態的
下面的程式碼清單展示了這個模式一個正確的實現
先前的ChannelHandler實現了滿足其被在多個管道使用時的多個需求,顧名思義,它被@Sharable註解了自己,並且它不包含任何的狀態,相反,下面的6.11程式碼清單就可能引起一些問題:
這個程式碼的問題是因為它是有狀態的,因為有一個count的變數,這個變數會計算該方法的呼叫,增加這個類的例項到ChannelPipeline中去就可能會出現錯誤,當它被併發的channel觸發的時候出現
總而言之,你必須保證你的ChannelHandler是執行緒安全的在你使用@Sharable的時候
WHY SHARE A CHANNELHANDLER? 在多個ChannelPipeline中使用同一個ChannelHandler的一個正常理由是多個Channel的統計資訊
我們對ChannelHandlerContext的討論做了總結,並且講解了它與其他元件之間的關係,下一個小節,我們討論一下異常處理
6.4 Exception handling
異常處理對於任意一個重大的系統都是一個很重要的模組,它可以以多種方式去完成這個模組,相應的,Netty提供了一些輸入輸出處理時產生異常的一些處理選項,這個小節將幫助你理解這些方式,並找出最合適滿足你需要的處理方式
6.4.1 Handling inbound exceptions
在輸入事件處理過程中一個異常丟擲時,這個異常將會在觸發該異常的ChannelInboundHandler的地方開始在ChannelPipeline傳播,為了處理這樣的異常,你需要在你的ChannelPipeline實現中重寫如下的方法
下面的程式碼清單向你展示一個簡單的異常處理例子:關閉channel然後打印出異常資訊
因為發生的異常可以繼續沿著輸入的方向傳播,這就保證了無論異常在哪裡發生,所有在ChannelPipeline中的業務邏輯都會處理,且所有的異常都會被捕獲處理
關於如何處理異常更多的情況下是取決你具體的應用程式,你可能會關閉channel連線,也可能去嘗試去恢復,當然,如果你沒有實現任何異常處理的方法,Netty將會記錄異常沒有被處理
總結如下:
1)預設的ChannelHandler的exceptionCaught的實現會把異常傳給管道中的下一個處理器
2)如果一個異常到達了一個管道的結尾,它將被記錄為未被處理
3)來定義自定義的處理,你重寫了exceptionCaught方法,這將是你自己的決定你是否決定將其接著傳播到下游處理器
6.4.2 Handling outbound exceptions
處理輸出操作的正常實現或者異常問題是基於以下幾點列出的機制:
1)每一個輸出操作返回一個ChannelFuture,註冊到ChannelFuture上的ChannelFutureListener會被通知操作是否成功或者失敗當操作完成的時候
2)幾乎所有的ChannelOutboundHandler都會傳遞一個ChannelPromise例項,作為ChannelFuture的子類,它也可以被監聽器管控來獲取非同步通知,但是ChannelPromise為實時通知提供可寫的方法
在ChannelFuture例項中增加一個ChannelFutureListener是為了呼叫addListener方法,有兩種方法可以完成這個實現,一個最最常用的方式是呼叫由輸出操作返回的ChannelFuture的addListener方法
下面的程式碼清單使用了這個方法來增加一個ChannelFutureListener,用來列印一次然後關閉Channel
第二個方式是通過在ChannelOutboundHandler方法中作為引數的傳遞的ChannelPromise增加一個ChannelFutureListener,下面的程式碼清單展示了與上面程式碼有相同功能的實現
TIPS:ChannelPromise的寫方法
通過呼叫ChannelPromise的setSuccess或者setFailure方法,你可以是呼叫者在ChannelHandler返回的時候,立馬知道操作的是否成功
怎麼才知道兩個方式哪個更好呢?如果你想要更仔細地處理異常,那麼你會發現使用程式碼清單6.13中更加合適,但是如果你想更加專業的處理異常,你會發現6.14顯得更加簡單
如果ChannelOutboundHandler自己本身發生了異常,那麼會發生什麼呢?這種情況下,Netty本身會通知註冊到相對應的ChannelPromise上的任意監聽器
6.5 Summary
在這個章節,我們討論了Netty的資料處理元件ChannelHandler,我們討論了多個ChannelHandler鏈在一起,討論了ChannelInboundHandler和ChannelOutboundHandler如何與ChannelPipeline互動的
下一個章節我們討論Netty的編碼抽象,這個將比直接使用底層的ChannelHandler實現來編寫編碼和解碼更加簡單
相關推薦
Netty in Action (十四) 第五章節 第三部分 ByteBufHolder,ByteBuf分配,計數引用
5.4 Interface ByteBufHolder 我們經常在ByteBuf中儲存一些正常資料之外,我們有時候還需要增加一些各式各樣的屬性值,一個Http響應體就是一個很好的例子,除了按照位元組傳輸過來的主體內容,還有狀態碼,cookie等資訊 Netty提供了By
Netty in Action (十六) 第六章節 第二部分 ChannelHandlerContext和異常處理
6.3 Interface ChannelHandlerContext 一個ChannelHandlerContext代表了一個ChannelHandler和ChannelPipeline之間的關係,ChannelHandlerContext創建於ChannelHandl
團隊作業8----第二次項目沖刺(Beta階段) 第六天
mas 發現 blog 項目 功能 程序 src 代碼 images BETA階段沖刺第六天 1.當天站立式會議 本次會議主要總結昨天任務完成情況,並分配新任務。 2.每個人的工作 (1) 成員 昨天已完成的工作 今天計劃完成的工作 莊健鵬(2014
第二次項目沖刺(Beta階段)--第六天
新的 nbsp ima ava str 方式 r文件 測試 blog 一、站立式會議照片 二、項目燃盡圖 三、項目進展 1、繼續完成docx文件的讀取,聽取助教的意見采用原型法,先簡單寫了一個可運行的docx
【第二組】項目沖刺(Beta版本)第六次每日例會 2017/7/24
ima size 界面優化 png 整理 strong 技術 eight logs 項目沖刺(Beta版本)第六次每日例會 開發小組:Hunter 沖刺經理:林貴淵 小組成員:林軒宇,張太,李明君,劉仁人 1、每日例會內容 (1)昨天做了什麽 1、林軒宇:Button音
加法變乘法——第六屆藍橋杯C語言B組(省賽)第六題
clu 自己 nbsp 加法 藍橋杯 重新 () std spa 原創 加法變乘法 我們都知道:1+2+3+ ... + 49 = 1225現在要求你把其中兩個不相鄰的加號變成乘號,使得結果為2015 比如:1+2+3+...+10*11+12+...+27*28+29+
學習筆記之計算機網路(王道考研) 第六章 應用層
在C/S模型中,伺服器總是處於開啟狀態(除非某人把它關了) 常見的使用C/S模型的英應用包括Web、檔案傳輸(FTP)、遠端登入和電子郵件等 C/S模型的主要特點: 網路中各計算機的地位不平等,伺服器可以通過對使用者許可權的限制來達到管理客戶機的目的
實現PHP伺服器+Android客戶端(Retrofit+RxJava)第六天推送的實現
廢話不多說,今天來說說近幾天的成果。 如何實現推送 android客戶端nio的使用 為啥要使用長連線 長連線的建立 php伺服器如何實現長連線 後期需要優化的部分 如何實現推送 推送的原理其實也很簡單,伺服器和客戶端實現長連線,實現了長連線之後就
軟體開發實訓(720科技)――第六課:轉換器和格式化、驗證器
4. JS SR R 3 30 03 3 V Va al li id da at to or r 範 例 jsr303-validator 應用程式展示了 JSR 303 輸入驗證的例子。這個應用程式是對 spring-validator 進行修改之後的版本,與之前的版本有一些區別。首先,它沒有 Pr
(資料結構)第六章 圖
圖 直觀顯示圖結構的方法:用小圓圈或小方塊代表頂點,用連線於其間的直線段或者曲線弧表示對應的邊。 圖:無向圖、有向圖及混合圖 深度優先搜尋實質功能:先將當前節點v標記為DISCOVERED(已發現)狀態,再逐一核對其各鄰居u的狀態並做相應處理。待其所有鄰居均以處理完畢之後,將頂點v置為V
後端碼農談前端(CSS篇)第六課:盒子模型
元素框的最內部分是實際的內容,直接包圍內容的是內邊距。內邊距呈現了元素的背景。內邊距的邊緣是邊框。邊框以外是外邊距,外邊距預設是透明的,因此不會遮擋其後的任何元素。 提示:背景應用於由內容和內邊距、邊框組成的區域。 一、CSS 內邊距屬性 屬性 描述 padding 簡寫屬性。作用是在一個宣告中
修理牧場 (25 分)第六章樹和二叉樹--Huffman樹-計算機17級 7-1
7-1 修理牧場 (25 分) 農夫要修理牧場的一段柵欄,他測量了柵欄,發現需要N塊木頭,每塊木頭長度為整數Li個長度單位,於是他購買了一條很長的、能鋸成N塊的木頭,即該木頭的長度是Li的總和。 但是農夫自己沒有鋸子,請人鋸木的酬金跟這段木頭的長度成正比。為簡
根據後序和中序遍歷輸出先序遍歷 (25 分)第六章樹和二叉樹作業1—二叉樹--計算機17級 7-1
7-1 根據後序和中序遍歷輸出先序遍歷 (25 分) 本題要求根據給定的一棵二叉樹的後序遍歷和中序遍歷結果,輸出該樹的先序遍歷結果。 輸入格式: 第一行給出正整數N(≤30),是樹中結點的個數。隨後兩行,每行給出N個整數,分別對應後序遍歷和中序遍歷結果,數字間以空格分隔
Netty原始碼分析 (十一)----- 拆包器之LengthFieldBasedFrameDecoder
本篇文章主要是介紹使用LengthFieldBasedFrameDecoder解碼器自定義協議。通常,協議的格式如下: LengthFieldBasedFrameDecoder是netty解決拆包粘包問題的一個重要的類,主要結構就是header+body結構。我們只需要傳入正確的引數就可以傳送和接收正確
Netty原始碼分析 (十二)----- 心跳服務之 IdleStateHandler 原始碼分析
什麼是心跳機制? 心跳說的是在客戶端和服務端在互相建立ESTABLISH狀態的時候,如何通過傳送一個最簡單的包來保持連線的存活,還有監控另一邊服務的可用性等。 心跳包的作用 保活Q:為什麼說心跳機制能保持連線的存活,它是叢集中或長連線中最為有效避免網路中斷的一個重要的保障措施?A:之所以說是&l
Linux命令(十八) 壓縮或解壓縮文件和目錄 gzip gunzip
配置 硬鏈接 名稱 log logs 壓縮文件 mark 底部 linux 目錄 1.命令簡介 2.常用參數介紹 3.實例 4.直達底部 命令簡介 和 zip 命令類似,gzip 用於文件的壓縮,gzip壓縮後的文件擴展名為 ".gz",gzip默認壓縮後會刪除源文
工作那些事(十一)談談碼農與農民工區別和發展之路 工作那些事(十二)如果哪一天,沒有了電腦 工作那些事(十三)再次失業
工作那些事系列連結快速通道,不斷更新中: 工作那些事(一)今年工作不好找 工作那些事(二)應聘時填寫個人資訊ABCD 工作那些事(三)什麼樣的公司能吸引你,什麼樣的公司適合你? 工作那些事(四)大公司VS小公司 工作那些事(五)談談專案資料整理和積累 工作那些事(六)談談
EOS智慧合約開發(十八)從EOS資料分析history_plugin外掛和MongoDB外掛區別
EOS資料 從EOS上線一段時間來看,他產生的Block已經遠遠超過了以太坊。以太坊在交易完成後,很容易過濾出交易資訊(如何獲取在我之前以太坊文章中有詳細描述)。EOS機制與以太坊有卻別,EOS如此大的資料量,我們就會問,EOS資料時如何獲取,查詢。今天我們就這個問題,給大家分析一下。
python學習之網站的編寫(HTML,CSS,JS)(十四)----------CSS的display行內標籤和塊級標籤的轉換,控制標籤是否顯示
行內標籤:有多大就佔多大,無法設定高度,寬度和邊距。 塊級標籤:佔一行,可以設定高度,寬度和邊距。 塊級標籤轉為行內標籤:display:inline 行內標籤轉為塊級標籤:display:block 還有一個特殊的轉換,既包含塊級標籤的屬性,又具有行內標籤的屬性,自己有多少佔多少,
Spring Boot 初級入門教程(十一) —— 打分離 jar 包、部署和測試(附原始碼)
分離 jar 包,也就是把工程原始碼打包到 *.jar,而把工程依賴的所有 lib 單獨生成,這樣打包的好處是,在依賴包沒有修改的情況下,部署時只需要上傳一次依賴包,每次部署的專案 jar 包很小,在伺服器網路不太好的情況下,這樣做是非常有必要的,因為上傳 20M 和 上傳 20K 的時間還是有