鑑於Iteye上的人氣越來越少,打算把上面的文章搬過來了。今天先搬Netty相關的。
下面是用excel畫的一個簡單的結構圖
- Channel是對最終I/O處理的封裝
- EventExecutor 封裝了負責處理I/O 事件的線程
- ChannelHandler 處理相關I/O Event的擴展接口,分爲ChannelInboundHandler和[*]ChannelOutboundHandler,分別處理不同流向的事件
- ChannelHandlerContext 對ChannelHandler相關信息的包裝
- ChannelPipeline 組裝多個ChannelHandlerContext的管道,I/O事件在這個管道中流動
姑且給角色A取名命令者,角色B取名執行者。所以這裏會有兩個過程。一個是命令者通知執行者。一個是執行者通知命令者。在網絡通信過程中這兩個角色容易理解,命令者就是執行應用邏輯的線程,執行者是底層執行具體I/O的線程。
具體體現到類上的,EventExecutor就是I/O操作的執行者了,命令者通知執行者的過程描述是ChannelOutboundInvoker,而執行者通知命令者的過程描述就是ChannelInboundInvoker,這裏的Inbound和Outbound是面向命令者來說的,而實際應用中的命令者就是應用邏輯了,netty本身作爲一個框架肯定就是服務於應用的。對比ChannelOutboundInvoker和ChannelInboundInvoker中的方法名稱,發現Inbound的中的都是firexxx,fire對通知是再形象不過的描述了。而Outbound中的都是xxx(ChannelPromise promise),命令口氣十足啊,同時還給了執行者一個ChannelPromise,相當於告訴了執行者執行完後,把執行結果放到指定的地方,命令者在接收到執行者執行完成的通知後,就去前面指定的ChannelPromise中去取結果。
ChannelPipeline描述的是命令者與執行者交互的過程,所以它既繼承了ChannelInboundInvoker也繼承了ChannelOutboundInvoker。
ChannelHandlerContext是針對ChannelHandler的包裝,處於ChannelPipeline中,所以它也同時實現了兩個。
Channel是負責與外部進行I/O的執行者的抽象,所以它繼承了ChannelOutboundInvoker。
首先分析下Channel接口,接口文檔中可以瞭解到:這個接口主要是封裝了一些網絡的I/O操作read,write,connect,bind。另外綁定了一下Channel相關的信息。ChannelConfig指定Channel的相關配置信息,ChannelPipeline負責命令者和執行者Channel之間的I/O事件傳遞。
有意思的是內部的UnSafe接口了,接口文檔描述的是之所以取名UnSafe是因爲不能從外部線程調用UnSafe接口中的方法,只能在Channel當前相關的I/O線程中調用。有一些接口除外,這個具體看下文檔。UnSafe中才是真正的I/O操作實現,裏面包含了register,bind,connect,disconnect,close,read,write,flush等操作,具體實現可以看子類了。
這裏先描述下具體I/O操作調用的流程,
應用->Channel的I/O操作->調用Pipeline相應的I/O操作->調用ChannelHandlerContext的相應I/O操作->調用ChannelHandler的相應操作->Channel.UnSafe中相關的I/O操作。
應用爲什麼不直接調用Channel.UnSafe接口中的I/O操作呢,而要繞一個大圈呢?因爲它是框架,要支持擴展。
執行者完成操作後,是如何通知命令者的呢?一般流程是這樣的:
Channel.UnSafe中執行相關的I/O操作,根據操作結果->調用ChannelPipeline中相應發fireXXXX()接口->調用ChannelHandlerContext中相應的fireXXXX()接口->調用ChannelHandler中相應方法->調用應用中的相關邏輯
後面將按照上圖中的各個元素逐一分析他們的源碼。