如何封裝一個非阻塞式 Java 網絡庫
1. 前言
到目前為止,我們已經學完了 Java 網絡編程的所有關鍵知識點,如果能將這些知識點靈活應用到項目中,那再好不過了。本小節將從實戰的角度出發,展示如何基于 Java NIO 封裝一個非阻塞式網絡庫。核心是采用事件反應器模型,將復雜的 SocketChannel、ServerSocketChannel、ByteBuffer、Selector 進行抽象,將繁瑣的數據讀寫操作加以封裝,以便應用程序調用。
本項目提供的完整代碼路徑:
2. 系統類圖
在 OOD 的思想體系下,現實世界中無論是具體的、還是抽象的事物,都是對象,現實世界就是由對象組成的。對象有自己的屬性和行為,對象之間可以產生聯系。把具有相同屬性和行為的對象叫做同一類對象,抽象出類。OOD 的思想非常符合人的思維方式,更容易建模和抽象。如果你對 OOD 不是很熟悉的話,可以查閱相關資料學習。
我們現在的工作是要把 Java NIO 中的各個組件加以抽象,抽象出一個或若干個類,通過 UML 展現出來,類圖如下:
下來我們就解釋一下以上幾個接口和實現類的功能:
類名 | 功能 |
---|---|
Poller | Java NIO Selector 事件多路復用機制的封裝,實現事件循環機制,是一個事件反應器,是一個功能實現類 |
IOHandler | 是 Poller 的配套類,響應accept、connect、read、write事件,是一個 Java 接口 |
SocketHandler | 是一個功能類,實現了 IOHandler 接口,將一些通用的邏輯加以封裝 |
Acceptor | 實現 TCP 服務器監聽功能,繼承自 SocketHandler |
TcpHandler | TCP 客戶端、服務器邏輯的封裝,繼承自 SocketHandler。主要完成客戶端連接,服務器接收新連接,數據收發,關閉連接的功能 |
IOAdapter | 事件循環機制向應用層提供的一個回調接口,一般由 IOHandler 調用 |
AbstractAdapter | 是一個 Java 接口,主要完成通用邏輯,實現了 IOAdapter 接口 |
Listener | 事件監聽接口,主要實現線程切換的功能 |
CustomEventObject | 代表一個具體事件,是 Listener 的配套類 |
IOThread | 對 Java 線程的封裝,聚合了 Poller 功能。我們說過 Java 的 Selector 其實是同步的,需要一個線程調用 select 監聽事件 |
ThreadPool | 對 IOThread 的封裝,提供線程池功能 |
3. 接口設計
軟件的接口是指軟件模塊對外提供的一組函數或者方法,目的是讓別的模塊訪問本模塊的功能,以達到組件復用的目的。根據模塊邏輯復雜度的不同,接口由分為:系統接口、子系統接口、模塊接口、子模塊接口、類接口。關于模塊、子模塊、類的應用都非常靈活,我們這里認為類就是最小的模塊。
本小節所說的接口是指 Java 接口。我們抽象了三個 Java 接口:Listener、IOHandler、IOAdapter,還有一個功能類 Poller?,F在對每個接口中的方法加以說明:
- Poller
類名 | 接口名 | 描述 |
---|---|---|
Poller | register | 將 IOHandler 實例添加到 Poller |
start | 啟動一個 Poller 實例 | |
close | 停止一個 Poller 實例 | |
poll | Poller 進入事件循環 |
- IOHandler
類名 | 接口名 | 描述 |
---|---|---|
IOHandler | handle_read | 是一個回調方法,當 Poller 監聽到某個 IOHandler 注冊的讀事件觸發時,調用 handle_read |
handle_write | 是一個回調方法,當 Poller 監聽到某個 IOHandler 注冊的寫事件觸發時,調用 handle_write | |
handle_accept | 是一個回調方法,當 Poller 監聽到某個 IOHandler 注冊的accept事件觸發時,調用 handle_accept | |
handle_connected | 是一個回調方法,當 Poller 監聽到某個 IOHandler 注冊的connected事件觸發時,調用 handle_connected | |
getSocketChannel | 用于獲取 IOHandler 對應的 SocketChannel 對象 |
IOHandler 是一個抽象接口,TcpHandler 需要實現此接口,當然你也可以實現其他協議,只需要擴展 IOHandler 的接口即可。
- IOAdapter
類名 | 接口名 | 描述 |
---|---|---|
IOAdapter | onAccept | 當 IOHandler 收到一個新的 TCP 連接時,在 handle_read 中回調此方法 |
onConnected | 當 io_hanIOHandlerdler 完成異步連接時,在 handle_connected 中回調此方法 | |
onRead | IOHandler 會在 handle_read 中回調此方法 | |
onWrite | IOHandler 會在 handle_write 中回調此方法 | |
onClose | IOHandler 收到連接被關閉時,回調此方法 | |
setSocketHandler | 向 IOAdapter 設置一個 IOHandler 對象 |
應用層需要實現 IOAdapter 的接口,并且要覆蓋接口中的方法,完成數據收發。
- Listener
類名 | 接口名 | 描述 |
---|---|---|
Listener | process | 處理異步事件 |
4. 總結
本小節主要是將前面小節介紹的 Java NIO 相關模塊進行一個抽象,形成一個非阻塞的 Java 網絡庫。采用的設計思想就是依賴倒轉,將復雜的網絡編程細節進行封裝,讓應用程序員不需要關注這些復雜的機制。
我們抽象出了一組接口和一組功能類,并對類的功能和接口中的方法進行了一一說明。本小節可以說是對整個系列內容的總結和實踐。