?
一、IoService接口
1、作用:IoService是創建服務的頂層接口,無論客戶端還是服務端,都是從它繼承實現的。
2、類結構
常用接口為:IoService,IoAcceptor,IoConnector
常用類為:NioSocketAcceptor,NioSocketConnector
類圖如下:
?
?
先提出兩個問題:
1. 為什么有了IoService接口還要定義AbstractIoService抽象類?
2. AbstractIoService抽象類與IoAcceptor(IoConnector)有什么區別?
分析:
? ? 1. IoService接口聲明了服務端的共有屬性和行為;
? ? 2. IoAcceptor接口繼承了IoService接口,并添加了服務端特有的接口屬性及方法,比如bind()方法,成為典型的服務端接口;
? ? 3. IoConnector接口同樣繼承了IoService接口,并添加了客戶端特有的接口屬性及方法,比如connect()方法,成為典型的客戶端接口;
---- IoService是IoAcceptor和IoConnector父接口,為什么不直接定義IoAcceptor和IoConnector接口呢,因為它們有共同的特點,比如共同屬性,管理服務的方法等,所有IoService的出現是為了代碼復用。
? ? 4. AbstractIoService實現了IoService中管理服務的方法,比如getFilterChainBuilder方法---獲得過濾器鏈;
----為什么有了IoService接口還要定義AbstractIoService抽象類?一樣為了代碼的復用!AbstractIoService抽象類實現了服務端或客戶端的共有的管理服務的方法,不需要讓IoService接口的子類重復的實現這些方法;
? ? 5. AbstractIoAcceptor抽象類繼承了AbstractIoService抽象類并實現了IoAcceptor接口,成為了擁有管理服務端實現功能的服務端類;我們常用的NioSocketAcceptor就是它的子類;
? ? 6. AbstractIoConnector抽象類繼承了AbstractIoService抽象類并實現了IoConnector接口,成為了擁有管理客戶端實現功能的客戶端類;我們常用的NioSocketConnector就是它的子類;
----AbstractIoService抽象類與IoAcceptor(IoConnector)有什么區別?很清楚,AbstractIoService抽象類實現的是共有的管理服務的方法,只有管理功能的一個類;而兩個接口卻是不同的兩個服務角色----一個客戶端,一個服務端。
//創建一個非阻塞的server端的Socket acceptor = new NioSocketAcceptor(); //創建一個非阻塞的客戶端 IoConnector connector = new NioSocketConnector();
獲得IoSession的配置對象IoSessionConfig,通過它可以設置Socket連接的一些選項。
a. void setReadBufferSize(int size)
這個方法設置讀取緩沖的字節數,但一般不需要調用這個方法,因為IoProcessor?會自動調整緩沖的大小。你可以調用setMinReadBufferSize()、setMaxReadBufferSize()方法,這樣無論IoProcessor?無論如何自動調整,都會在你指定的區間。
b. void setIdleTime(IdleStatus status,int idleTime):
?
這個方法設置關聯在通道上的讀、寫或者是讀寫事件在指定時間內未發生,該通道就進入空閑狀態。一旦調用這個方法,則每隔idleTime都會回調過濾器、IoHandler中的sessionIdle()方法。
?
c. void setWriteTimeout(int time):
這個方法設置寫操作的超時時間。
d. void setUseReadOperation(boolean useReadOperation):
這個方法設置IoSession?的read()方法是否可用,默認是false。
?
?
// 獲得IoSessionConfig對象 IoSessionConfig cfg=acceptor.getSessionConfig(); // 設置讀取數據的緩沖區大小() cfg.setReadBufferSize(2048); // 讀寫通道10秒內無操作進入空閑狀態 cfg.setIdleTime(IdleStatus.BOTH_IDLE, 10); // 寫操作超時時間10秒 cfg.setWriteTimeout(10);?
Mina 最主要的工作就是把底層傳輸的字節碼轉換為 Java 對象,提供給應用程序;或者把應用程序返回的結果轉換為字節碼,交給底層傳輸 。這些都是由 IoFilter 完成的,因此 IoFilter 是 Mina 的精髓所在。
在 Mina 程序中, IoFilter 是必不可少的;有了它, Mina 的層次結構才異常清晰:
IoFilter?? ----?? 消息過濾
IoHandler? ----?? 業務處理
??? Filter ,過濾器的意思。 IoFilter , I/O 操作的過濾器。 IoFilter 和 Servlet 中的過濾器一樣,主要用于攔截和過濾網絡傳輸中 I/O 操作的各種消息。在 Mina 的官方文檔中已經提到了 IoFilter 的作用:
( 1 )記錄事件的日志( Mina 默認提供了 LoggingFilter )
( 2 )測量系統性能
( 3 )信息驗證
( 4 )過載控制
( 5 )信息的轉換 ( 主要就是編碼和解碼 )
( 6 )和其他更多的信息
??? IoService 實例會綁定一個 DefaultIoFilterChainBuilder ---- 過濾器鏈,我們把自定義的各種過濾器( IoFilter )自由的插放在這個過濾器鏈上了,類似于一種可插拔的功能!
常用接口為: IoFilter , IoFilterChainBuilder
常用類為: IoFilterAdapter , DefaultIoFilterChainBuilder
ProtocolCodecFilter , LoggingFilter
類圖如下:
先提出兩個問題:
1. 在IoService中如何添加多個IoFilter?
2. 如何自定義協議編解碼器?
分析:
a. IoFilter有2個實現類:IoFilterAdapter是個抽象的適配器類,我們可以根據需要擴展這個類,并且有選擇的覆蓋過濾器的方法;所有方法的默認把事件轉發到下一個過濾器;查看源碼如下:
?
?
public void sessionOpened(NextFilter nextFilter, IoSession session)throws Exception { nextFilter.sessionOpened(session); }?
?
b .ReferenceCountingFilter封裝了IoFilter實例,監看調用該filter的對象的個數,如果沒有任何對象調用該IoFilter,就自動銷毀IoFilter;查看源碼如下:
?
?
public class ReferenceCountingFilter implements IoFilter { private final IoFilter filter; private int count = 0; public ReferenceCountingFilter(IoFilter filter) { this.filter = filter; } public void init() throws Exception { // no-op, will init on-demand in pre-add if count == 0 } public void destroy() throws Exception { } ……………略?
?
c. 實現 IoFilterAdapter 的類有多個,但是我們使用最多的就是
ProtocolCodecFilter---- 它是我們自定義編解碼器的入口?
添加過濾器----在IoService中如何添加多個IoFilter?如何代碼,我添加了2個過濾器:LoggingFilter和TextLineCodecFactory(源碼為入門的服務端程序)
// 創建一個非阻塞的server端的Socket acceptor = new NioSocketAcceptor(); // 設置日志過濾器 acceptor.getFilterChain().addLast("logger",new LoggingFilter()); // 設置過濾器(使用Mina提供的文本換行符編解碼器) acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset .forName("UTF-8"), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue()))); // 獲得IoSessionConfig對象 IoSessionConfig cfg = acceptor.getSessionConfig(); // 讀寫通道10秒內無操作進入空閑狀態 cfg.setIdleTime(IdleStatus.BOTH_IDLE, 10); // 綁定邏輯處理器 acceptor.setHandler(new Demo1ServerHandler()); // 綁定端口 acceptor.bind(new InetSocketAddress(PORT)); logger.info("服務端啟動成功... 端口號為:" + PORT);
?
如果要是使用LoggingFilter類,則需要需要導入slf4j-log4j12-1.7.5.jar、slf4j-api-1.7.5.jar、log4j-1.2.13.jar三個包,然后在src目錄下面添加log4j的配置文件
?
?
log4j.rootLogger=DEBUG,MINA,file log4j.appender.MINA=org.apache.log4j.ConsoleAppender log4j.appender.MINA.layout=org.apache.log4j.PatternLayout log4j.appender.MINA.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss,SSS} %-5p %c{1} %x - %m%n log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/minademos.log log4j.appender.file.MaxFileSize=5120KB log4j.appender.file.MaxBackupIndex=10 log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[VAMS][%d] %p | %m | [%t] %C.%M(%L)%n
?
?四、IoHandler接口
?
IoHandler是Mina實現其業務邏輯的頂級接口;它相當簡單,你就理解它是根據事件觸發的簡單應用程序即可。
在IoHandler中定義了7個方法,根據I/O事件來觸發對應的方法:
?
import java.io.IOException; 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; }
?
sessionCreated:當一個新的連接建立時,由I/O processor thread調用;
?
sessionOpened:當連接打開是調用;
?
messageReceived:當接收了一個消息時調用;
?
messageSent:當一個消息被(IoSession#write)發送出去后調用;
?
sessionIdle:當連接進入空閑狀態時調用;
?
sessionClosed:當連接關閉時調用;
?
exceptionCaught:當實現IoHandler的類拋出異常時調用;
?
? ? 一般情況下,我們最關心的只有messageReceived方法,接收消息并處理,然后調用IoSession的write方法發送出消息!(注意:這里接收到的消息都是Java對象,在IoFilter中所有二進制數據都被解碼啦!)
?
? ? 一般情況下很少有人實現IoHandler接口,而是繼承它的一個實現類IoHandlerAdapter,這樣不用覆蓋它的7個方法,只需要根據具體需求覆蓋其中的幾個方法就可以!
?
Iohandler的7個方法其實是根據session的4個狀態值間變化來調用的:
?
Connected:會話被創建并使用;
?
Idle:會話在一段時間(可配置)內沒有任何請求到達,進入空閑狀態;
?
Closing:會話將被關閉(剩余message將被強制flush);
?
Closed:會話被關閉;
?
?
狀態轉換圖如下
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
