文章目錄
- 前言
- Java NIO 工作原理
- Selector 的創建
- ServerSocketChannel 的創建
- ServerSocketChannel 注冊 Selector
- 對事件的處理
- 總結
前言
上篇文章《Netty 入門指南》主要涵蓋了 Netty 的入門知識,包括 Netty 的發展歷程、核心功能與組件,并且通過實例演示了如何使用 Netty 構建一個 HTTP 服務器。由于 Netty 的抽象程度較高,因此理解起來可能會更加復雜和具有挑戰性,所以本文將通過 Java NIO 的處理流程與 Netty 的總體流程比較,并結合 Netty 的源碼更加清晰地理解Netty。
Java NIO 工作原理
首先我們知道Netty是基于Java NIO的一個網絡應用框架,是在其基礎上進行封裝和擴展(所以在深入了解Netty之前,建議先對Java NIO有一定的了解),所以二者對網絡的連接、讀取和寫入的操作方式是相似的。
如上圖的Java NIO的處理流程,與Java NIO代碼示例結合,可以看到,將 ServerSocketChannel
注冊到 Selector
并監聽各個事件后,Selector
在接受到事件請求后我們業務代碼對其進行判斷并對應處理,在使用Netty時我們似乎不需要寫這些代碼,甚至都沒有看見Selector
、ServerSocketChannel
這些字眼,那這些代碼在Netty中怎么體現的,我們扒開褲子看個究竟:
以上文Netty構建的HTTP服務器示例為例,直接關注 ServerSocketChannel
、Selector
是什么時候創建的,事件是什么時候注冊以及處理的。
Selector 的創建
其實看了上篇的Netty入門,可以知道 EventLoop
負責處理各種事件,所以可以盲猜一下,Selector
應該是在 NioEventLoopGroup
中創建的,look
在 NioEventLoopGroup
的構造方法中調用 JDK 的 SelectorProvider
創建了Selector
,也就是 Java NIO 的代碼。
ServerSocketChannel 的創建
關于 ServerSocketChannel
的創建,直接找綁定端口的方法,如下圖
同樣,在 Netty 的代碼 NioServerSocketChannel
的newChannel()
中也看到 Java NIO 的代碼。
ServerSocketChannel 注冊 Selector
下圖中 ServerSocketChannel
在創建后為其分配了一個 EventLoop
并開啟新的線程(這也是Netty 多線程異步的體現),最終在 doRegister()
調用了JDK 的接口注冊了Selector
并監聽了事件,看見 selectionKey
應該什么都清楚了吧。
對事件的處理
既然 ServerSocketChannel
注冊了Selector
并監聽了事件,那接下來就是當有事件來時 EventLoop
對其進行處理,直接看 NioEventLoop
中的代碼,因為他是通過新的線程啟動的,所以直接看 run()
processSelectedKeysPlain()
中的代碼熟悉吧,是監聽到了某個事件可以進行處理了,下面是對讀事件的處理
圖中 ChannelPipeline
采用了責任鏈模式是對事件的處理通道,方便擴展。所以 Netty 中的讀取事件與 Java NIO 的關系如下圖。
總結
所以在接觸 Netty 的之前一定要先掌握 Java NIO,本文只是介紹了 Java NIO 在 Netty 中的體現、Netty 對 Java NIO 的封裝,讓大家更方便的理解 Netty,并不涉及 Netty 的高效、強大的設計之處,下文將會對此進行介紹。