netty源碼解解析(4.0)-8 ChannelPipeline的設計
阿新 • • 發佈:2018-12-25
rst 分配 active ace 時間 rev remove 設置 bject 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。
netty源碼解解析(4.0)-8 ChannelPipeline的設計