請戳GitHub原文: github.com/wangzhiwubi…
更多文章關注:多執行緒/集合/分散式/Netty/NIO/RPC
- Java高階特性增強-集合
- Java高階特性增強-多執行緒
- Java高階特性增強-Synchronized
- Java高階特性增強-volatile
- Java高階特性增強-併發集合框架
- Java高階特性增強-分散式
- Java高階特性增強-Zookeeper
- Java高階特性增強-JVM
- Java高階特性增強-NIO
- RPC
- zookeeper
- JVM
- NIO
- 其他更多
ChannelHandler並不處理事件,而由其子類代為處理:ChannelInboundHandler攔截和處理入站事件,ChannelOutboundHandler攔截和處理出站事件。ChannelHandler和ChannelHandlerContext通過組合或繼承的方式關聯到一起成對使用。事件通過ChannelHandlerContext主動呼叫如fireXXX()和write(msg)等方法,將事件傳播到下一個處理器。注意:入站事件在ChannelPipeline雙向連結串列中由頭到尾正向傳播,出站事件則方向相反。 當客戶端連線到伺服器時,Netty新建一個ChannelPipeline處理其中的事件,而一個ChannelPipeline中含有若干ChannelHandler。如果每個客戶端連線都新建一個ChannelHandler例項,當有大量客戶端時,伺服器將儲存大量的ChannelHandler例項。為此,Netty提供了Sharable註解,如果一個ChannelHandler狀態無關,那麼可將其標註為Sharable,如此,伺服器只需儲存一個例項就能處理所有客戶端的事件。
核心類圖
上圖是ChannelHandler的核心類類圖,其繼承層次清晰,我們逐一分析。
1.ChannelHandler
ChannaleHandler 作為最頂層的介面,並不處理入站和出站事件,所以介面中只包含最基本的方法:
// Handler本身被新增到ChannelPipeline時呼叫
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
// Handler本身被從ChannelPipeline中刪除時呼叫
void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
// 發生異常時呼叫
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
複製程式碼
其中也定義了Sharable標記註解:
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Sharable {
// no value
}
複製程式碼
作為ChannelHandler的預設實現,ChannelHandlerAdapter有個重要的方法isSharable(),程式碼如下:
public boolean isSharable() {
Class<?> clazz = getClass();
// 每個執行緒一個快取
Map<Class<?>, Boolean> cache =
InternalThreadLocalMap.get().handlerSharableCache();
Boolean sharable = cache.get(clazz);
if (sharable == null) {
// Handler是否存在Sharable註解
sharable = clazz.isAnnotationPresent(Sharable.class);
cache.put(clazz, sharable);
}
return sharable;
}
複製程式碼
這裡引入了優化的執行緒區域性變數InternalThreadLocalMap,將在以後分析,此處可簡單理解為執行緒變數ThreadLocal,即每個執行緒都有一份ChannelHandler是否Sharable的快取。這樣可以減少執行緒間的競爭,提升效能。
2.ChannelInboundHandler
ChannelInboundHandler處理入站事件,以及使用者自定義事件:
// 類似的入站事件
void channeXXX(ChannelHandlerContext ctx) throws Exception;
// 使用者自定義事件
void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;
複製程式碼
ChannelInboundHandlerAdapter作為ChannelInboundHandler的實現,預設將入站事件自動傳播到下一個入站處理器。其中的程式碼高度一致,如下:
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.fireChannelRead(msg);
}
複製程式碼
3.ChannelOutboundHandler
ChannelOutboundHandler處理出站事件:
// 類似的出站事件
void read(ChannelHandlerContext ctx) throws Exception;
複製程式碼
同理,ChannelOutboundHandlerAdapter作為ChannelOutboundHandler的事件,預設將出站事件傳播到下一個出站處理器:
@Override
public void read(ChannelHandlerContext ctx) throws Exception {
ctx.read();
}
複製程式碼
4.ChannelDuplexHandler
ChannelDuplexHandler則同時實現了ChannelInboundHandler和ChannelOutboundHandler介面。如果一個所需的ChannelHandler既要處理入站事件又要處理出站事件,推薦繼承此類。 至此,ChannelHandler的核心類已分析完畢,接下來將分析一些Netty自帶的Handler。
請戳GitHub原文: https://github.com/wangzhiwubigdata/God-Of-BigData
關注公眾號,內推,面試,資源下載,關注更多大資料技術~
大資料成神之路~預計更新500+篇文章,已經更新60+篇~ 複製程式碼