本節主要介紹 Netty ChannelHandler 事件概述,並詳細介紹各個事件方法的觸發時機,爲下篇關於事件傳播機制打下堅實基礎。
NIO 相關的核心類圖如下:
下面一一對上述類做一個簡單的介紹,下文還會其進行更爲詳細的解讀。
- ChannelHandler
Netty Channel事件的基礎接口,只定義與 Handler 的管理接口相關,具體如下:- void handlerAdded(ChannelHandlerContext ctx)
在調用 DefaultChannelPipeline 的 addLast(add*) 將事件監聽器添加到事件處理鏈條時調用。 - void handlerRemoved(ChannelHandlerContext ctx)
在調用DefaultChannelPipeline 的 addLast(add*) 發生異常時被調用;當通道關閉後,通道取消註冊後,同時會觸發通道移除事件,具體調用入口:DefaultChannelPipeline 的內部類 HeadContext 的 channelUnregistered。
- void handlerAdded(ChannelHandlerContext ctx)
- ChannelInboundHandler
入端類型的事件處理器。- void channelRegistered(ChannelHandlerContext ctx)
通道註冊到 Selector 時觸發。客戶端在調用 connect 方法,通過 TCP 建立連接後,獲取 SocketChannel 後將該通道註冊在 Selector 時或服務端在調用bind 方法後創建 ServerSocketChannel,通過將通道註冊到 Selector 時監聽客戶端連接上時被調用。 - void channelUnregistered(ChannelHandlerContext ctx)
通道取消註冊到Selector時被調用,通常在通道關閉時觸發,首先觸發channelInactive 事件,然後再觸發 channelUnregistered 事件。 - void channelActive(ChannelHandlerContext ctx)
通道處於激活的事件,在 Netty 中,處於激活狀態表示底層 Socket 的isOpen() 方法與 isConnected() 方法返回 true。 - void channelInactive(ChannelHandlerContext ctx)
通道處於非激活(關閉),調用了 close 方法時,會觸發該事件,然後觸發channelUnregistered 事件。 - void channelRead(ChannelHandlerContext ctx, Object msg)
通道從對端讀取數據,當事件輪詢到讀事件,調用底層 SocketChanne 的 read 方法後,將讀取的字節通過事件鏈進行處理,NIO 的觸發入口爲AbstractNioByteChannel 的內部類 NioByteUnsafe 的 read 方法。 - void channelReadComplete(ChannelHandlerContext ctx)
處理完一次通道讀事件後觸發,在 Netty 中一次讀事件處理中,會多次調用SocketChannel 的 read方法。觸發入口爲AbstractNioByteChannel 的內部類NioByteUnsafe 的 read 方法。 - void userEventTriggered(ChannelHandlerContext ctx, Object evt)
觸發用戶自定義的事件,目前只定義了ChannelInputShutdownEvent(如果允許半關閉(輸入端關閉而服務端不關閉))事件。 - void channelWritabilityChanged(ChannelHandlerContext ctx)
Netty 寫緩存區可寫狀態變更事件(可寫–》不可寫、不可寫–》可寫),入口消息發送緩存區ChannelOutboundBuffer。
- void channelRegistered(ChannelHandlerContext ctx)
- void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
異常事件。 - ChannelOutboundHandler
出端類型的事件處理器。- void bind(ChannelHandlerContext ctx, SocketAddress add, ChannelPromise p)
調用ServerBootstrap 的 bind 方法的處理邏輯。綁定操作,服務端在啓動時調用bind方法時觸發(手動調用bind)。 - void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,SocketAddress localAddress, ChannelPromise promise)
連接操作,客戶端啓動時調用connect方法時觸發(手動調用connect)。 - void disconnect(ChannelHandlerContext ctx, ChannelPromise promise)
斷開連接操作(手動調用disconnect) - void close(ChannelHandlerContext ctx, ChannelPromise promise)
關閉通道,手動調用Channel#close方法時觸發。(手動調用close) - void deregister(ChannelHandlerContext ctx, ChannelPromise promise)
調用Channel#deregister時觸發。(手動調用deregister)。 - void read(ChannelHandlerContext ctx) throws Exception
註冊讀事件,並不是觸發網絡讀寫事件。 - void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception
調用調用 Channel 的 write(底層 SocketChannel 的 write)時觸發。 - void flush(ChannelHandlerContext ctx)
調用調用Channel#flush(SocketChannel#flush)時觸發。
- void bind(ChannelHandlerContext ctx, SocketAddress add, ChannelPromise p)
- ChannelDuplexHandler
雙向 Handler,包含 Inbound 和 outbound 事件。 - ByteToMessageDecoder
解碼器:字節流解碼成一條一條的消息(Message、協議對象)。 - MessageToByteEncoder
編碼器:消息(協議對象)編碼成二進制字節流。 - AbstractTrafficShapingHandler
流量整形,將在後續章節中詳細介紹。
上述詳細的介紹了NettyChannel的類繼承體系,並重點介紹了ChannelInboundHandler 與 ChannelOutboundHandler 每個方法的含義已經觸發時機,接下來再談一點我對這兩個 Handler 的一些理解。
ChannelInboundHandler:入端操作,可以看出基本上是都是由事件選擇器(NIO Selector事件就緒選擇)進行觸發,事件名稱以 channel 開頭,例如channelRead。
ChannelOutboundHanlder:出端操作,其觸發點除了 read 事件外都是通過調用api(例如bind、connect、close、write)。
本文就介紹到這裏了,主要目的是讓大家對 Netty ChannelHandler 有一個基本的認識,爲後續文章打下堅實的基礎。
最後以一個思考題結束本文的講解:ChannelInboundHandler 的channelRead 事件與 ChannelOutboundHandler 的 read 事件有什麼區別呢?
溫馨提示:如果需要與筆者關於上述問題進行交流,可以加筆者微信:dingwpmz。
好了,本文就介紹到這裏了,您的點贊與轉發是對我持續輸出高質量文章最大的鼓勵。
歡迎加筆者微信號(dingwpmz),拉您如技術交流加羣探討,筆者優質專欄目錄:
1、源碼分析RocketMQ專欄(40篇+)
2、源碼分析Sentinel專欄(12篇+)
3、源碼分析Dubbo專欄(28篇+)
4、源碼分析Mybatis專欄
5、源碼分析Netty專欄(18篇+)
6、源碼分析JUC專欄
7、源碼分析Elasticjob專欄
8、Elasticsearch專欄(20篇+)
9、源碼分析MyCat專欄
10、源碼分析 Canal
11、源碼分析Kafka