摘要:只有在詳盡的測試之后才應設置為這值使用的默認采樣率檢測并報告任何發現的泄漏。這是默認級別,適合絕大部分情況使用默認的采樣率,報告所發現的任何的泄漏以及對應的消息被訪問的位置類似于但是其將會對每次對消息的訪問都進行采樣。
ChannelHandler Channel生命周期
狀態 | 描述 |
---|---|
ChannelUnregistered | Channel已經被創建,但未注冊到EventLoop |
ChannelRegistered | Channel已經被注冊到了EventLoop |
ChannelActive | Channel處于活動狀態(已經連接到它的遠程節點)。現在Channel可以接受和發送數據 |
ChannelInActive | Channel沒有連接到遠程節點 |
一般Channel的生命周期順序ChannelRegistered -> ChannelActive -> ChannelInactive -> ChannelUnregistered。
當Channel的狀態發生變化時,將會生成對應的事件。與此同時,這些事件會被轉發給ChannelPipeline中的ChannelHandler。
ChannelHandler生命周期ChannelHandler定義的生命周期操作,在ChannelHandler被添加到ChannelPipeline中或者被從ChannelPipeline中移除時會調用這些方法。這些方法中都可以接受一個ChannelHandlerContext參數。
類型 | 描述 |
---|---|
handlerAdded | 當把ChannelHandler添加到ChannelPipeline中時被調用 |
handlerRemoved | 當從ChannelHandler在ChannelPipeline移除時調用 |
exceptionCaught | 當處理過程中在ChannelPipeline中有錯誤產生時被調用 |
Netty中定義了下面兩個重要的ChannelHandler接口:
ChannelInboundHandler——處理入站數據以及各種狀態變化
CHannelOutboundHandler——處理出站數據并且允許攔截所有的操作
ChanneInboundHandler接口類型 | 描述 |
---|---|
channelRegistered | 當Channel已經注冊到它的EventLoop并且能夠處理I/O時被調用 |
channelUnregistered | 當Channel從它的EventLoop注銷并且無法處理任何I/O時被調用 |
channelActive | 當Channel處于活動狀態時被調用;Channel已經連接/綁定并且已經就緒 |
channelInactive | 當Channel離開活動狀態并且不再連接它的遠程節點時被調用 |
channelReadComplete | 當Channel的一個讀操作完成時被調用 |
channelRead | 當從Channel讀取數據時被調用 |
channelWritabilityChanged | 當Channel的可寫狀態發生改變時被調用。用戶可以確保寫操作不會完成的太快(以避免發生OutOfMemoryError)或者可以在Channel變為再次可寫時恢復寫入。Channel的isWriteable()方法可以來檢測Channel的可寫性。與可寫性相關的閥值可以通過Channel.config().setWriteHighWaterMark()和Channel.config().setWriteLowWaterMark()方法來設置 |
userEventTriggered | 當ChannelInboundHandler.fireUserEventTriggered()方法被調用時被調用。 |
當某個ChannelInboundHandler的實現重寫channelRead()方法時,它將負責顯示地釋放與池化的ByteBuf實例相關的內存。ReferenceCountUtil.release()
Netty會使用WARN級別的日志消息記錄未釋放的資源,但是以這種方式管理資源可能非常繁瑣,Netty采用SimpleChannelInboundHandler來簡化這種操作。
ChannelOutboundHandler接口出站操作和數據將由ChannelOutboundHandler處理。它的方法將被Channel、ChannelPipeline以及ChannelHandlerContext調用。
ChannelOutboundHandler可以按需推遲操作或者事件。
類型 | 描述 |
---|---|
bind(ChannelHandlerContext, SockertAddress, ChannelPromise) | 當請求將Channel綁定到本地地址時被調用 |
connect(ChannelHandlerContext, SocketAddress, SockertAddress, ChannelPromise) | 當請求將Channel連接到遠程節點時被調用 |
disconnect(ChannelHandlerContext, ChannelPromise) | 當請求將Channel從遠程節點斷開時被調用 |
close(ChannelHandlerContext, ChannelPromise) | 當請求關閉Channel時被調用 |
deregister(ChannelHandlerContext, ChannelPromise) | 當請求將Channel叢它的EventLoop注銷時被調用 |
read(ChannelHandlerContext) | 當請求從Channel讀取更多的數據時被調用 |
flush(ChannelHandlerContext) | 當請求通過Channel將入隊數據沖刷到遠程節點時被調用 |
write(ChannelHandlerContext, Object, ChannelPromise) | 當請求通過Channel將數據寫到遠程節點時被調用 |
ChannelOutboundHandler中的大部分方法都需要一個ChannelPromise參數,方便在操作完成時獲取通知。ChannelPromise時ChannelFuture的一個子類,定義了一些可寫方法,如setSuccess()和setFailure()方法
ChannelHandler適配器ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter兩個適配器分別提供了ChannelInboundHandler和ChannelOutboundHandler的基本實現。通過擴展抽象類ChannelHandlerAdapter,它們獲得了它們共同的超接口ChannelHandler的方法。
ChannelHandlerAdapter提供了isSharable(),如果其對應的實現被注解標注為Sharable,這方法將返回true,表示它可以被添加到多個ChannelPipeline。
ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter中的方法體調用了其相關聯的ChannelHandlerContext上的等效方法,從而將事件轉發到了ChannelPipeline中的下一個ChannelHandler中。
資源管理Netty目前定義了4種泄露檢測級別:
級別 | 描述 |
---|---|
DISABLED | 禁用泄漏檢測。只有在詳盡的測試之后才應設置為這值 |
SIMPLE | 使用1%的默認采樣率檢測并報告任何發現的泄漏。這是默認級別,適合絕大部分情況 |
ADVANCED | 使用默認的采樣率,報告所發現的任何的泄漏以及對應的消息被訪問的位置 |
PARANOID | 類似于ADVANCED,但是其將會對每次(對消息的)訪問都進行采樣。會對性能有很大影響,只能在調試階段使用 |
java -Dio.netty.leakDetectionLevel=ADVANCED
如果一個消息被消費或者丟棄了,并且沒有傳遞給ChannelPipeline中的下一個ChannelOutboundHandler,那么用戶就有責任調用ReferenceCountUtil.release()。如果消息到達了實際的傳輸層,那么當它被寫入時或者Channel關閉時,都將被自動釋放。
ChannelPipeline接口每一個新創建的Channel都將會被分配一個新的ChannelPipeline。這項關聯是永久性的;Channel既不能附加另外一個ChannelPipeline,也不能分離當前的。
根據事件的起源,事件將會被ChannelInboundHandler或者ChannelOutboundHandler處理。隨后,會調用ChannelHandlerContext實現,它將被轉發給同一超類型的下一個ChannelHandler。
ChannelHandlerContext使ChannelHandler能夠和它的ChannelPipeline以及其他的ChannelHandler交互。ChannelHandler可以通知其所屬的ChannelPipeline中的下一個ChannelHandler,甚至可以動態修改它所屬的ChannelPipeline。
在ChannelPipeline傳播事件時,它會測試ChannelPipeline中的下一個ChannelHandler的類型是否和事件的運動方向相匹配。如果不匹配,ChannelPipeline將跳過該ChannelHandler并前進到下一個,直到它找到和該事件所期望的方向相匹配的為止。(ChannelHandler可以同時實現ChannelInboundHandler和ChannelOutboundHandler接口)
修改ChannelPipelineChannelHandler可以通過添加、刪除或者替換其他的ChannelHandler來實時地修改ChannelPipeline的布局。
名稱 | 描述 |
---|---|
addFirst(),addBefore(),addAfter(),addLast() | 將一個ChannelHandler添加到ChannelPipeline |
remove() | 將一個ChannelHandler從ChannelPipeline中移除 |
replace() | 將ChannelPipeline中的一個ChannelHandler替換為另一個ChannelHandler |
get() | 通過類型或者名稱返回ChannelHandler |
context() | 返回和ChannelHandler綁定的ChannelHandlerContext |
names() | 返回ChannelPipeline中所有的ChannelHandle的名稱 |
ChannelPipeline的API公開了用于調用入站和出站操作的附加方法,用于通知ChannelInboundHandler在ChannelPipeline中所發生的事件。
名稱 | 描述 |
---|---|
fireChannelRegistered | 調用ChannelPipeline中下一個ChannelInboundHandler的channelRegistered(ChannelHandlerContext)方法 |
fireChannelUnregistered | 調用ChannelPipeline中下一個ChannelInboundHandler的channelUnregistered(ChannelHandlerContext)方法 |
fireChannelActive | 調用ChannelPipeline中下一個ChannelInboundHandler的channelActive(ChannelHandlerContext) |
fireChannelInActive | 調用ChannelPipeline中下一個ChannelInboundHandler的channelInactive(ChannelHandlerContext)方法 |
fireExceptionCaught | 調用ChannelPipeline中下一個ChannelInboundHandler的exceptionCaught(ChannelHandlertext, Throwable)方法 |
fireUserEventTriggerd | 調用ChannelPipeline中下一個ChannelInboundHandler的userEventTriggered(ChannelHandlertext, Object)方法 |
fireChannelRead | 調用ChannelPipeline中下一個ChannelInboundHandler的channelRead(ChannelHandlertext, Object msg)方法 |
fireChannelReadComplete | 調用ChannelPipeline中下一個ChannelInboundHandler的channelReadComplete(ChannelHandlertext)方法 |
fireChannelWritabilityChanged | 調用ChannelPipeline中下一個ChannelInboundHandler的channelWritabilityChanged(ChannelHandlertext)方法 |
ChannelPipelin的出站操作
名稱 | 描述 |
---|---|
bind | 將Channel綁定到一個本地地址,將調用ChannelPipeline中的下一個ChannelOutboundHandler的bind(ChannelHandlerContext,Socket,ChannelPromise)方法 |
connect | 將Channel連接到一個遠程地址,這將調用ChannelPipeline中的下一個ChannelOutboundHandler的connect(ChannelHandlerContext,Socket,ChannelPromise)方法 |
disconnect | 將Channel斷開連接。這將調用ChannelPipeline中的下一個ChannelOutboundHandler的disconnect(ChannelHandlerContext,Socket,ChannelPromise)方法 |
close | 將Channel關閉。這將調用ChannelPipeline中的下一個ChannelOutboundHandler的close(ChannelHandlerContext,ChannelPromise)方法 |
deregister | 將Channel從它先前分配的EventExecutor(即EventLoop)中注銷,這將調用ChannelPipeline中的下一個ChannelOutboundHandler的deregister(ChannelHandlerContext,ChannelPromise)方法 |
flush | 沖刷Channel所有掛起的寫入。這將調用ChannelPipeline中的下一個ChannelOutboundHandler的flush(ChannelHandlerContext)方法 |
write | 將消息寫入Channel。這將調用ChannelPipeline中的下一個ChannelOutboundHandler的write(ChannelContext,Object msg,ChannelPromise)方法。這并不會將消息寫入底層的Socket,而只會將它放入到隊列中。要將它寫入到Socket,需要調用flush或者writeAndFlush方法 |
writeAndFlush | 先調用write再調用flush的便利方法 |
read | 請求從Channel中讀取更多的數據。這將調用ChannelPipeline中的下一個ChannelOutboundHandler的read(ChannelHandlerContext)方法 |
ChannelPipeline保存了與Channel相關聯的ChannelHandler
ChannelPipeline可以根據需要,通過添加或者刪除ChannelHandler來動態修改
ChannelPipeline有著豐富的API調用,以響應入站和出站事件
ChanneHandlerContext接口ChannelHandlerContext代表了ChannelHandler和ChannelPipeline之間的關聯。每當有ChannelHandler添加到ChannelPipeline中時,都會創建ChannelHandlerContext。ChannelHandlerContext的主要功能是管理它所關聯的ChannelHandler和在同一個ChannelPipeline中的其他ChannelHandler之間的交互。
ChannelHandlerContext有很多方法,其中一些方法也存在于Channel和ChannelPipeline本身上。如果調用Channel或者ChannelPipeline上的方法,它們將沿著整個ChannelPipeline進行傳播,而調用ChannelHandlerContext上的相同方法,則從當前所關聯的ChannelHandler開始,并且只會傳播給位于該ChannelHandler的下一個能夠處理該事件的ChannelHandler。
方法名稱 | 描述 |
---|---|
alloc | 返回和這個實例相關的Channel所配置的ByteBufAllocator |
bind | 綁定到給定的SocketAddress,并返回ChannelFuture |
channel | 返回綁定到這個實例的Channel |
close | 關閉Channel,并返回ChannelFuture |
connect | 連接給定的SocketAddress,并返回ChannelFuture |
deregister | 從之前分配的EventExecutor注銷,并返回ChannelFuture |
disconnect | 從遠程節點斷開,并返回ChannelFuture |
executor | 返回調度事件的EventExecutor |
fireChannelActive | 觸發對下一個ChannelInboundHandler上的channelActive()方法的調用 |
fireChannelInActive | 觸發下一個ChannelInboundHandler上的channelInActive()方法 |
fireChannelRead | 觸發對下一個ChannelInboundHandler上的channelRead()方法 |
fireChannelReadComplete | 觸發對下一個ChannelInboundHandler上的channelReadComplete()方法的調用 |
fireChannelRegistered | 觸發對下一個ChanneInboundHandler上的fireChannelRegistered方法的調用 |
fireChannelUnregistered | 觸發對下一個ChannelInboundHandler上的fireChannelUnregistered方法的調用 |
fireChannelWritabilityChanged | 觸發對下一個ChannelInboundHandler上的fireChannelWritabilityChanged方法的調用 |
fireExceptionCaught | 觸發對下一個ChannelInboundHandler上的fireExceptionCaught方法的調用 |
fireUserEventTriggered | 觸發對下一個ChannelInboundHandler上的fireUserEventTriggered(Object evt)方法的調用 |
handler | 返回綁定到這個實例的ChannelHandler |
isRemoved | 如果從關聯的ChannelHandler已經被從ChannelPipeline中移除則返回true |
name | 返回這個實例的唯一名稱 |
pipeline | 返回這個實例相關聯的ChannelPipeline |
read | 將數據從Channel讀取到第一個入站緩沖區;如果讀取成功則觸發一個channelRead事件,并(在最后一個消息被被讀取完成后)通知ChannelInboundHandler的channelReadComplete(ChannelHandlerContext)方法 |
write | 通過這個實例寫入消息并經過ChannelPipeline |
writeAndFlush | 通過這個實例寫入并沖刷消息并經過ChannelPipeline |
ChannelHanlderContext和ChannelHandler之間的關聯是永遠不會改變的,所以緩存對它的引用是安全的
ChannelHandlerContext上的方法產生的事件流更短,應該利用這個特性盡可能的獲得最大的性能
使用ChannelHandlerContext讓ChannePipeline從某個特定的點開始傳播的原因:
為了減少將事件傳經對它不感興趣的ChannelHandler所帶來的開銷
為了減少將事件傳經那些可能會對它感興趣的ChannelHandler
要想調用從某個特定的ChannelHandler開始處理的過程,必須獲取到在(ChannelPipeline)該ChannelHandler之前的hannelHandler所關聯的ChannelHandlerContext。這個ChannelHandlerContext將調用和它所關聯的ChannelHandler之后的ChannelHandler。
一個ChannelHandler可以從屬于多個ChannelPipeline,所以它(同一個ChannelHandler)也可以綁定到多個ChannelHandlerContext實例。用于這種用法的ChannelHandler必須使用@Shareable注解標注;否則將它添加到多個ChannelPipeline時將會觸發異常。顯而易見,為了安全地被用于多個并發的Channel(即連接),這樣的ChannelHandler必須是線程安全的。
為何要共享一個ChannelHandler?
在多個ChannelPipeline中安裝同一個ChannelHandler的一個常見原因是用于收集跨越多個Channel的統計信息。
如果在處理入站事件的過程中有異常被拋出,那么它將從它在ChannelInboundHandler里被觸發的那一點開始流經ChannelPipeline。如果想要處理這種類型的入站異常,必須在你的ChannelInboundHandler中重寫exceptionCaught(ChannelHandlerContext,Throwable)
異常會按照入站方向流動,所以一般處理異常的邏輯通常都在最后一個ChannelInboundHandler中實現
ChannelHandler.exceptionCaught()的默認實現是簡單的將當前異常轉發給ChannelPipeline中的下一個ChannelHandler
如果異常到達了ChannelPipeline的尾端,它將會被記錄為未被處理
要想定義自定義的處理邏輯,你需要重寫exceptionCaught()方法,然后決定是否將該異常傳播出去。
處理出站異常用于處理出站操作中的正常完成以及異常的選項,都基于以下的通知機制:
每個出站操作都返回一個ChannelFuture。注冊到ChannelFuture的ChannelFutureListener將在操作完成時被通知該操作是成功了還是出錯了。
幾乎所有的ChannelOutboundHandler上的方法都會傳入一個ChannelPromise的實例。作為ChannelFuture的子類,ChannelPromise也可以被分配用于異步通知的監聽器。
添加ChannelFuturListener只需要調用ChannelFuture實例上的addListener(ChannelFutureListener)方法,并且有兩種不同的方式去實現。第一種是調用出站操作(如write方法)所返回的ChanneFuture上的addListener方法;第二種方式是將ChannelFutureListener添加到即將作為參數傳遞給ChannelOutboundHandler的方法的ChannelPromise
通過調用ChannelPromise上的setSuccess和setFailure方法,可以使一個操作的狀態在ChannelHandler的方法返回給其調用者時即刻被感知到。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69705.html
摘要:提示不支持文件的讀取有一個客戶有這樣的需求,需要在里使用組件,把一個文檔的內容,插入另一個文檔的指定頁內。由于兩個文檔的內容都不是固定的,所以不能使用的功能。當讀取到指定的分頁符之后,再讀取的內容,跟著前面的內容插入,最后保存新的文檔。 提示:不支持.doc文件的讀取有一個客戶有這樣的需求,需要在ThinkPHP里使用PHPWord組件,把一個文檔(DOC1)的內容,插入另一個文檔(D...
摘要:要運行儀表板,請使用注解主類,然后訪問并將儀表板指向客戶端應用程序中的單個實例的端點。連接到使用的端點時,必須信任服務器使用的證書,如果證書不受信任,則必須將證書導入,以便儀表板成功連接到流端點。 Hystrix超時和Ribbon客戶端 使用包裝Ribbon客戶端的Hystrix命令時,要確保將Hystrix超時配置為長于配置的Ribbon超時,包括可能進行的任何可能的重試,例如,如果...
摘要:整理一些最近幾天學習的一些知識點,好記性不如爛筆頭,寫下來敲一遍代碼為自己寫哈。這點就不獻丑了,也是才學習。脫離文檔流的元素,其高度不再計算到高度內。 整理一些最近幾天學習CSS的一些知識點,好記性不如爛筆頭,寫下來敲一遍代碼為自己寫哈。 左右兩欄或三欄布局1、常用方法是給div加float浮動方式實現,加了浮動后div不再獨占一行。 2、還有就是position屬性實現,通過posi...
摘要:整理一些最近幾天學習的一些知識點,好記性不如爛筆頭,寫下來敲一遍代碼為自己寫哈。這點就不獻丑了,也是才學習。脫離文檔流的元素,其高度不再計算到高度內。 整理一些最近幾天學習CSS的一些知識點,好記性不如爛筆頭,寫下來敲一遍代碼為自己寫哈。 左右兩欄或三欄布局1、常用方法是給div加float浮動方式實現,加了浮動后div不再獨占一行。 2、還有就是position屬性實現,通過posi...
閱讀 2669·2021-11-25 09:43
閱讀 2475·2021-09-22 15:29
閱讀 989·2021-09-22 15:17
閱讀 3631·2021-09-03 10:36
閱讀 2228·2019-08-30 13:54
閱讀 1747·2019-08-30 11:23
閱讀 1167·2019-08-29 16:58
閱讀 1294·2019-08-29 16:14