這一節咱們將確認Netty提供的核心功能是什麼,以及它們怎麼構成一個完整的網絡應用開發堆棧。java
Netty使用它本身的緩存API來表示字節序列而不是NIO的ByteBuffer。Netty的新緩存類——ChannelBuffer,完全解決了ByteBuffer的問題,知足了網絡應用開發者的平常需求。這裏列舉幾個很酷的特色:web
當在通訊層傳輸數據時,數據常常須要被組合或者切分。好比一次裝載被分紅多個包,可是常常須要組合起來解碼。
傳統方式來講,多個包的數據經過複製到一個新的字節緩存而組合起來。
Netty支持零複製實現,經過讓一個新的ChannelBuffer「指向」全部要求組合的緩存,從而避免了複製操做。
瀏覽器
傳統Java的I/O API對不一樣的傳輸類型提供不一樣的類和方法。舉個例子,java.net.Socket和java.net.DatagramSocket沒有公共父類所以它們在執行socket I/O的方式徹底不同。緩存
這種不匹配的結果就是使得應用程序從一種傳輸方式移植成另外一種變得十分困難。也就是說你須要支持額外的傳輸方式由於應用程序的網絡層常常涉及到重寫。邏輯上,許多協議能夠在不僅一種傳輸方式,好比TCP/IP、UDO/IP、SCTP和串行通訊上運行。安全
更糟的是,Java的新I/O(NIO)API繼承了老阻塞I/O(OIO)API的不兼容性,而且在下一個版本NIO.2(AIO)繼續這樣作。由於這些API在設計和表現特色上徹底不一樣,你常常被迫在應用程序開始實現以前就須要肯定好依賴那種API。網絡
舉個例子,你可能想用OIO方式開始由於你服務的客戶數量很小且用OIO寫一個socket服務比用NIO要簡單得多。可是,當你的業務呈指數級上升而後你須要同時服務成千上萬的客戶時,麻煩就大了。你也能夠用NIO方式開始,可是這可能會阻礙開發速度,畢竟NIO的選擇器API很複雜。數據結構
Netty擁有統一的異步I/O接口——Channel,它抽象了點對點通訊要求的全部操做。只要你用一種Netty傳輸寫的應用程序,能夠在其餘Netty傳輸上運行。Nett經過統一的API提供了必要的傳輸方式:架構
要從一種傳輸方式切換到另外一種,只須要改動幾行代碼,好比選擇另外一個ChannelFactory實現。框架
你甚至可使用還沒發佈的新傳輸方式,好比串行通訊傳輸,一樣替換幾行構造器調用的代碼。再者,你也能夠經過繼承核心API實現本身的傳輸方式。異步
一個定義良好的並可擴展性高的事件模型是一個事件驅動應用程序的前提。Netty針對I/O有一個定義良好的事件模型。你能夠在不破壞已有代碼的狀況下實現你本身的事件類,由於每個事件類都根據一個嚴格的類層次體系區別於其餘事件類。這是另外一個和其餘框架的不一樣點。不少NIO框架都沒有或者頗有限的事件模型概念。若是它們提供了擴展,就會常常在嘗試增長自定義事件類時破壞已有代碼。
一個ChannelEvent由一個ChannelPipeline裏的一列ChannelHandler來處理。這個管道實現了一個過濾鏈模式的高級形式,讓使用者徹底控制一個事件如何被處理以及管道內的handler如何相互聯繫。舉個例子,你能夠規定數據從socket讀取時作點什麼:
public class MyReadHandler implements SimpleChannelHandler { public void messageReceived(ChannelHandlerContext ctx, MessageEvent evt) { Object message = evt.getMessage(); // Do something with the received message. ... // And forward the event to the next handler. ctx.sendUpstream(evt); } }
你也能夠規定一個handler在接收一個寫請求時作點什麼:
public class MyWriteHandler implements SimpleChannelHandler { public void writeRequested(ChannelHandlerContext ctx, MessageEvent evt) { Object message = evt.getMessage(); // Do something with the message to be written. ... // And forward the event to the next handler. ctx.sendDownstream(evt); } }
以前「用POJO替代ChannelBuffer」那一節證明了,把協議編解碼從業務邏輯中分離出來一般是一個好主意。可是從零開始實現有一些困難。你須要處理信息分片。有一些協議是多層的(創建在其餘低級協議基礎上)。還有一些協議在單機系統上實現特別困難。
所以,一個好的網絡應用框架須要提供一個可擴展的、可重用的、可單元測試的和多層級的編解碼器框架,產生可維護的用戶編解碼器。
Netty提供了一系列基礎和高級的編解碼器,能夠解決你在寫一個協議編解碼器是遭遇的大多數問題,不管編解碼器是否簡單,是二進制的仍是文本的。
不像阻塞I/O,在NIO支持SSL是個值得正視對任務。你不能簡單得包裝一個流對數據進行加密解密,你必需要用到javax.net.ssl.SSLEngine。SSLEngine是一個跟SSL自己同樣複雜的狀態機。你須要處理全部可能的狀態,如密碼套件、加密密鑰協商、證書交換以及驗證。此外,SSL甚至不是徹底線程安全的。
在Netty,SslHandler負責對外屏蔽SSLEngine全部細枝末節,你只須要配置SslHandler而後添加到你的ChannelPipeline中。SslHandler同時讓你能夠很容易實現相似StartTLS的高級特性。
HTTP絕對是互聯網最流行的協議。如今已經有一系列HTTP實現,好比Servlet容器。那麼爲何Netty還要本身實現HTTP呢?
Netty的HTTP支持和現有的HTTP庫很不同。它讓你能夠徹底控制HTTP在底層的消息交換。由於從根本上來講,它就是一個HTTP編解碼器和HTTP消息類的結合,沒有相似強制線程模型這樣的限制。也就是說,你能夠按照你但願的工做方式來實現HTTP客戶端和服務端。你擁有全部HTTP規範內的控制權,包括線程模型、鏈接生命週期和分塊編碼。
基於它的高可定製性,你能夠寫一個高效的HTTP服務:
WebSocket在單TCP socket上實現一個雙向全雙工通訊通道,用於web瀏覽器和web服務端端數據交互。
WebSocket協議由IETF標準化爲RFC 6455。
Netty實現了RFC 6455和一系列舊版本規範。
Google Protocal Buffers是一個高效二進制協議的快速實現。憑藉ProtobufEncoder和ProtobufDecoder,你能夠將Goodgle Protocal Buffers編譯程序生成的信息類轉化爲Netty編解碼器。
這一節,咱們從特色出發回顧了Netty的整體架構。Netty擁有一個簡單且至今仍強大的架構。它由三個組件組成——buffer,channel和事件模型,全部高級特性都是在這三個組件的基礎上創建的。只要你理解了這三個組件是如何一塊兒工做的,你就不難理解這節簡要說起的那些高級特性。