請戳GitHub原文: https://github.com/wangzhiwubigdata/God-Of-BigDatagit
更多文章關注:多線程/集合/分佈式/Netty/NIO/RPCgithub
ChannelHandler並不處理事件,而由其子類代爲處理:ChannelInboundHandler攔截和處理入站事件,ChannelOutboundHandler攔截和處理出站事件。ChannelHandler和ChannelHandlerContext經過組合或繼承的方式關聯到一塊兒成對使用。事件經過ChannelHandlerContext主動調用如fireXXX()和write(msg)等方法,將事件傳播到下一個處理器。注意:入站事件在ChannelPipeline雙向鏈表中由頭到尾正向傳播,出站事件則方向相反。
當客戶端鏈接到服務器時,Netty新建一個ChannelPipeline處理其中的事件,而一個ChannelPipeline中含有若干ChannelHandler。若是每一個客戶端鏈接都新建一個ChannelHandler實例,當有大量客戶端時,服務器將保存大量的ChannelHandler實例。爲此,Netty提供了Sharable註解,若是一個ChannelHandler狀態無關,那麼可將其標註爲Sharable,如此,服務器只需保存一個實例就能處理全部客戶端的事件。面試
上圖是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標記註解:markdown
@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的緩存。這樣能夠減小線程間的競爭,提高性能。併發
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); }
ChannelOutboundHandler處理出站事件:
// 相似的出站事件 void read(ChannelHandlerContext ctx) throws Exception;
同理,ChannelOutboundHandlerAdapter做爲ChannelOutboundHandler的事件,默認將出站事件傳播到下一個出站處理器:
@Override public void read(ChannelHandlerContext ctx) throws Exception { ctx.read(); }
ChannelDuplexHandler則同時實現了ChannelInboundHandler和ChannelOutboundHandler接口。若是一個所需的ChannelHandler既要處理入站事件又要處理出站事件,推薦繼承此類。
至此,ChannelHandler的核心類已分析完畢,接下來將分析一些Netty自帶的Handler。
請戳GitHub原文: https://github.com/wangzhiwubigdata/God-Of-BigData 關注公衆號,內推,面試,資源下載,關注更多大數據技術~ 大數據成神之路~預計更新500+篇文章,已經更新60+篇~