1. 程式人生 > >netty原始碼解解析(4.0)-8 ChannelPipeline的設計

netty原始碼解解析(4.0)-8 ChannelPipeline的設計

io.netty.channel.ChannelPipeline   設計原理      上圖中,為了更直觀地展示事件處理順序, 故意有規律地放置兩種handler的順序,實際上ChannelInboundHandler和ChanneOutboundHandler的順序可以是任意,取決於使用者呼叫add方法把handler方在哪裡。     ChannelPipeline的特性:   1. 它是一個雙向連結串列   2. 每個節點持有一個ChannelHandler例項,這個例項可以是ChannelInboundHandler型別或ChannelOutboundHandler型別,   3. ChannelInboundHandler型別的handler只處理inbound事件,ChannelInboundHandler只處理outbound事件。   4. inbound事件處理順序是由連結串列頭到連結串列尾,outbound事件的處理順序是由連結串列尾到連結串列頭。   5. inbound事件由netty內部觸發,最終由netty外部的程式碼消費。outbound事件由netty外部的程式碼觸發,最終由netty內部消費。   介面設計
  ChannelPipeline介面定義的方法分為三種類型:連結串列管理的方法、觸發outbound事件的方法、觸發inbound事件的方法。   連結串列管理的方法 新增:addFirst, addLast, addAfter, addBefore。 刪除:removeFirst, removeLast, remove。 替換:replace。 查詢:first, last, get。   觸發outbound事件的方法
bind(SocketAddress, ChannelPromise) connect(SocketAddress, SocketAddress, ChannelPromise) write(Object, ChannelPromise) flush() read() disconnect(ChannelPromise) close(ChannelPromise) deregister(ChannelPromise)   觸發inbound事件的方法
fireChannelRegistered() fireChannelActive() fireChannelRead(Object) fireChannelReadComplete() fireExceptionCaught(Throwable) fireUserEventTriggered(Object) fireChannelWritabilityChanged() fireChannelInactive() fireChannelUnregistered()       Channel,EventLoop,ChannelPipeline,EventExecutor和ChannelHandler之間的關係    每個channel持有一個eventLoop, channel.unsafe的方法會在這個eventLoop中執行。那麼問題來了,使用add方法向channelPiple中新增一個channelHandler,這個handler的方法在哪裡執行呢?下面以addLast為例看看新增方法。 ChannelPipeline addLast(ChannelHandler... handlers) ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers) ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler)     channelPiple負責為每個新新增的handler分配一個eventExecutor。如果你呼叫了帶grop引數的方法新增handler ,channelPiple會從group中取出一個eventExecutor分配給這個handler, 這時handler中的回撥方法會在這個eventExecutor執行緒中執行,否則channelPiple會把channel的eventLoop當成eventExecutor分配給這個handler,這時這個handler的回撥方法會在eventLoop的執行緒中執行。這個兩者有什麼不同呢?如果沒你沒有給handler指定group,它將會和channel的I/O操作共享執行緒資源,它能得到多少執行緒資源取決於eventLoop的ioRatio屬性的設定,執行時間過長的handler的回撥方法會影響I/O操作。如果指定了group,handler的回撥方法和channel的I/O操作將會被隔離到不同的執行緒中。在高併發情況下,強烈建議為不同功能的handler指定不同的group。 每個channel例項在建立的時候,它自己負責建立一個channelPiple例項。隨後這個channel會被註冊到一個eventLoop中,eventLoop負責處理channel上觸發的I/O事件,把I/O事件轉換成對channel.unsafe方法的呼叫。unsafe負責做實際的I/O操作,根據需要呼叫channelPiple觸發事件。channelPiple依次呼叫合適的handler處理事件。這裡的"依次”和“合適”的含義是:
  • 如果是inbound事件,會從頭到尾按順序呼叫雙向連結串列上的ChannelInboundHandler型別的handler。
  • 如果是outbound事件,會從尾到頭按順序呼叫雙向連結串列上的ChannelOutboundHandler型別的handler。
  piplePile確保一個handler呼叫始終在一個唯一的eventExecutor中,這個eventExecutor可能是channel的eventLoop,也可能是從使用者指定的eventExecutorGroup中分配到的一個executor。