解析Mina代碼三部曲
首先,Mina是什么?能幫我們做什么?我研究一個新技術的時候,首先問的就是這樣的問題。我個人的理解就是Mina是一個關注于通訊層的框架,任何需要底層通訊的應用,都可以使用它。更詳細準確的介紹,請看官方網站http://mina.apache.org/
Mina的優勢:
1. 用NIO實現,無需太多線程。可以處理的并發量更大。
2. 對于應用層來說,編程更方便。
好了廢話少說,先看個Demo吧
- public static void main(String[] args) throws IOException {
- // 創建Acceptor
- IoAcceptor acceptor = new NioSocketAcceptor();
- // 注冊filter
- acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
- acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
- // 注冊你的業務處理類
- acceptor.setHandler( new TimeServerHandler() );
- // 配置參數
- acceptor.getSessionConfig().setReadBufferSize( 2048 );
- acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
- // 讓Acceptor在綁定的地址偵聽
- acceptor.bind( new InetSocketAddress(PORT) );
- }
- public interface IoHandler {
- void sessionCreated(IoSession session) throws Exception;
- void sessionOpened(IoSession session) throws Exception;
- void sessionClosed(IoSession session) throws Exception;
- void sessionIdle(IoSession session, IdleStatus status) throws Exception;
- void exceptionCaught(IoSession session, Throwable cause) throws Exception;
- void messageReceived(IoSession session, Object message) throws Exception;
- void messageSent(IoSession session, Object message) throws Exception;
- }
首先new一個Acceptor,可以看出,Acceptor是我們要操作的服務器對象。然后,向Acceptor里注冊了兩個filter。filter的概念類似于web服務器里的filter。filter處于你的業務端代碼和具體的發送數據代碼之間,它負責過濾或者說處理傳遞過來的信息。業務處理代碼,寫在Handler里。
代碼結構相當的清晰。我們需要填寫的業務代碼就是 Handler 和 Filter了。它們倆很相似,但是在概念上是有區別的。filter事實上主要是處理底層的通信字節流,通信協議等,一般跟業務邏輯沒什么關系。Handler是專門暴露給應用開發者,用來填寫業務處理代碼的。
看看下面的圖便知道了

#p#
Mina暴露給開發者的接口主要是IoAcceptor(服務器端)或者IoConnector(客戶端)。Mina內部具體是怎么實現偵聽,處理連接的呢?我們先來介紹一下Mina的方法哲學或者說術語吧。
IoSession
IoSession: IoSession是一個客戶連接的抽象,整個通訊框架可以說,都是圍繞著IoSession工作的。
IoAcceptor: 初始化服務器,用的就是它
IoProcessor: 負責處理IoSession,包括創建,移除,讀寫事件的處理
IoFilter: 過濾消息或者說消息處理(通訊層的)
IoHandler: 消息處理(應用邏輯層的)
通訊層的核心類,事實上是IoAcceptor,IoProcessor,IoSession。在這里我們只分析IoAcceptor模式,也就是服務器端的代碼。客戶端的代碼與此類似,大家可以自己研究。
首先,調用IoAcceptor.bind()方法時,服務器已經初始化完畢,這時服務器就在指定的端口上開始偵聽客戶端發來的連接請求。
當IoAcceptor偵聽到客戶端請求時,它就會把這個請求交給IoProcessor進行處理。然后IoAcceptor回去繼續偵聽。顯然,IoAcceptor的工作流程就是 偵聽 --> 傳遞請求 --> 繼續偵聽。
IoProcessor得任務則是處理這些連接的IO事件。顯然IoProcessor不可能和IoAcceptor在同一個線程里運行。他們兩個分工不同,可以并發執行。Mina內部事實上維護了一個IoProcessor對象池,對象池的默認大小是CPU個數+1.也就是說,如果你的機器是4核的,可能就有5個IoProcessor(可以理解為線程)同時工作。
看看下面的示意圖吧,一圖勝千言:

#p#
在這里主要分析IoAcceptor 和 IoProcessor。
IoAcceptor比較簡單,它的核心代碼都在AbstractPollingAccetor里,輪詢代碼在它的內部類Accetpor里的run方法里。請看下面的UML圖:

IoProcessor比較復雜,它的主要代碼是在AbstractPollingProcessor里的,輪詢代碼在它的內部類Processor里的run方法實現。值得注意的是,IoAcceptor所持有的IoProcessor引用,事實上是一個對象池。對象池負責調度某個Processor來處理請求。下面是UML類圖

【編輯推薦】
- 巧解使Eclipse崩潰的JVM terminated問題
- JVM terminated令Eclipse崩潰問題的解決
- Java編譯過程與c/c++編譯過程有何不同
- 淺談jvm.dll裝載過程與源代碼分析
- Java虛擬機(JVM)中的內存設置詳解