在上一篇文檔中我們已經(jīng)了解了IoFilter的用法和其在Mina中的作用,作為Mina數(shù)據(jù)傳輸過(guò)程中比較重要的組件,IoFilter起到了承上啟下的作用----接收數(shù)據(jù),編/解碼,將數(shù)據(jù)傳遞到邏輯層,當(dāng)數(shù)據(jù)傳遞地到邏輯層時(shí),IoFilter的使命就完成了,那么邏輯層的數(shù)據(jù)由誰(shuí)來(lái)處理呢?如何處理的?這就是本文要講述的內(nèi)容----IoHandler。
?
在介紹IoFilter的時(shí)候,文中首先是從IoFilter的結(jié)構(gòu)和其在Mina中的作用談起的,最后添加了一個(gè)使用IoFilter的例子,之前我將其傳給幾個(gè)同學(xué)看時(shí),感覺(jué)這種方式比較晦澀,應(yīng)該將例子提到前面,由于時(shí)間的關(guān)系我不能在對(duì)IoFilter 的介紹做過(guò)多的修改,所以在本篇文檔中我就先以一個(gè)例子開(kāi)頭,介紹IoHandler,希望這種講述方式能對(duì)你理解Mina有更多的幫助。
?
好了,言歸正傳,我們的例子還是以上篇文檔中的IoFilter的例子為基礎(chǔ),在此基礎(chǔ)上著重突出IoHandler的作用。
ServerMain:
public class ServerMain {
public static void main(String[] args) throws IOException {
SocketAddress address = new InetSocketAddress
("localhost", 4321);
IoAcceptor acceptor = new SocketAcceptor();
IoServiceConfig config = acceptor.getDefaultConfig
();
// 配置數(shù)據(jù)的編解碼器
config.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new
ObjectSerializationCodecFactory()));
config.getFilterChain().addLast("logger", new
LoggingFilter());
// 綁定服務(wù)器端口
acceptor.bind(address, new ServerHandler());
System.out.println(" 服務(wù)器開(kāi)始在 8000 端口監(jiān)聽(tīng)
.......");
}
}
ServerHandler:
public class ServerHandler extends IoHandlerAdapter {
// 創(chuàng)建會(huì)話
public void sessionOpened(IoSession session) throws
Exception {
System.out.println(" 服務(wù)器創(chuàng)建了會(huì)話 ");
session.write(" 服務(wù)器創(chuàng)建會(huì)話時(shí)發(fā)送的信息 。");
}
// 發(fā)送信息
public void messageSent(IoSession session, Object message)
throws Exception {
}
// 接收信息
public void messageReceived(IoSession session, Object
message)
throws Exception {
}
}
ClientMain:
public class ClientMain {
public static void main(String[] args) {
SocketAddress address = new InetSocketAddress
("localhost", 4321);
IoConnector connector = new SocketConnector();
IoServiceConfig config =
connector.getDefaultConfig();
// 配置數(shù)據(jù)的編解碼器
config.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new
ObjectSerializationCodecFactory()));
config.getFilterChain().addLast("logger", new
LoggingFilter());
// 連接到服務(wù)器
connector.connect(address, new ClientHandler());
System.out.println(" 已經(jīng)連接到了服務(wù)器 " + address);
}
}
ClientHandler:
public class ClientHandler extends IoHandlerAdapter {
// 發(fā)送信息
public void messageSent(IoSession session, Object message)
throws Exception {
}
// 接收信息
public void messageReceived(IoSession session, Object
message)
throws Exception {
System.out.println(" 客戶端接收到的服務(wù)器的信息是 "
+ message);
}
}
?
上面給出里這個(gè)例子中的主要的代碼,當(dāng)先后啟動(dòng)服務(wù)器和客戶端后,服務(wù)器會(huì)在客戶端連接到服務(wù)器后發(fā)送一個(gè)字符串的消息。這個(gè)消息的發(fā)送就是在IoHandler中發(fā)送的。IoHandler在Mina中屬于業(yè)務(wù)層,這里的IoHandler更相是J2EE中的Servlet的作用,在IoHandler中你可以不用考慮底層數(shù)據(jù)的封裝和轉(zhuǎn)換,前提是你已經(jīng)在IoFilter中已經(jīng)完成了數(shù)據(jù)的轉(zhuǎn)換。這里需要提到的一個(gè)是,所謂數(shù)據(jù)的轉(zhuǎn)換,是指將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成Java中的可用對(duì)象或者是基本類型的數(shù)據(jù)。由于網(wǎng)絡(luò)傳輸中傳輸?shù)亩际嵌M(jìn)制數(shù)據(jù),這就需要有一個(gè)專門的數(shù)據(jù)轉(zhuǎn)換層,就Mina中的編解碼器來(lái)實(shí)現(xiàn)這個(gè)功能。如果使用RMI,對(duì)于這個(gè)問(wèn)題應(yīng)該不陌生,二進(jìn)制和對(duì)象之間的轉(zhuǎn)化過(guò)程其實(shí)就是對(duì)象的序列化和反序列化的過(guò)程。關(guān)于Mina中實(shí)現(xiàn)對(duì)象的序列化和反序列化會(huì)在后續(xù)的文檔中詳細(xì)介紹,在此不在贅述。
?
既然IoHandler是邏輯層,我們就用IoHandler實(shí)現(xiàn)一個(gè)簡(jiǎn)單的邏輯實(shí)現(xiàn)。先聽(tīng)一個(gè)小故事:一個(gè)淘氣的小孩要去KFC買漢堡,由于KFC生意比較好,人比較多,服務(wù)員忙不過(guò)來(lái),于是KFC專門設(shè)立了一個(gè)自動(dòng)售漢堡的機(jī)器,這個(gè)機(jī)器只是一個(gè)簡(jiǎn)單的數(shù)據(jù)收發(fā)裝置,(由于漢堡的價(jià)格時(shí)常變化,所以價(jià)格會(huì)實(shí)時(shí)更新,因此該機(jī)器需要和KFC的漢堡的價(jià)格服務(wù)器相連)小朋友買漢堡時(shí)只要向機(jī)器中投入硬幣,機(jī)器就會(huì)查詢服務(wù)器,看價(jià)格是否符合,若符合,則送給小朋友一個(gè)漢堡
,若不符合則提示小朋友錢不夠,買不到這個(gè)漢堡。
?
上面是我自己虛構(gòu)的一個(gè)小故事,我們先不管現(xiàn)實(shí)中的KFC是如何運(yùn)作的,我們就當(dāng)故事是真的了,那么現(xiàn)在這個(gè)小的項(xiàng)目分配給了我們,我們需要抽象出它的需求:
客戶端要向服務(wù)器發(fā)送數(shù)據(jù),查詢價(jià)格,根據(jù)價(jià)格是否合理給出相應(yīng)的顯示服務(wù)器接收客戶度的價(jià)格查詢請(qǐng)求,根據(jù)服務(wù)器中存儲(chǔ)的價(jià)格信息,返回響應(yīng)的結(jié)果。
根據(jù)上面的需求,我們使用Mina來(lái)實(shí)現(xiàn)上面的服務(wù)器和客戶端,程序的代碼如下(完整代碼在附件中):
KFCFoodPriceHandler(服務(wù)器句柄):
public class KFCFoodPriceHandler extends IoHandlerAdapter {
// 創(chuàng)建會(huì)話
public void sessionOpened(IoSession session) throws
Exception {
// System.out.println(" 服務(wù)器創(chuàng)建了會(huì)話 ");
}
// 接收信息
public void messageReceived(IoSession session, Object
message)
throws Exception {
HashMap<String, Object> map = (HashMap<String,
Object>) message;
String buythings = (String) map.get("購(gòu)買");
// System.out.println(" 服務(wù)器接收到的信息 " +
buythings);
if (buythings.equals("漢堡")) {
HashMap<String, Object> map2 = new
HashMap<String, Object>();
map2.put("食品", "漢堡");
map2.put("價(jià)格", 4);
session.write(map2);
} else if (buythings.equals("雞翅")) {
HashMap<String, Object> map2 = new
HashMap<String, Object>();
map2.put("食品", "雞翅");
map2.put("價(jià)格", 5);
session.write(map2);
} else {
session.write(" 該種物品已經(jīng)出售完畢,謝謝
惠顧!");
}
}
}
KFCSellerHandler(客戶端句柄):
public class KFCSellerHandler extends IoHandlerAdapter {
private Integer childInputMoney_Ham = 4;
private Integer childInputMoney_Chick = 5;
// 創(chuàng)建會(huì)話
public void sessionOpened(IoSession session) throws
Exception {
HashMap<String, Object> map = new
HashMap<String, Object>();
map.put("購(gòu)買", "漢堡");
session.write(map);
}
// 接收信息
public void messageReceived(IoSession session, Object
message)
throws Exception {
// System.out.println(" 客戶端接收到的服務(wù)器的信息是 "
// + (HashMap<String, Object>)
message);
HashMap<String, Object> priceInfor =
(HashMap<String, Object>) message;
// System.out.println("============" +
priceInfor.get("食品"));
String foodName = (String) priceInfor.get("食品");
if (foodName.equals("漢堡")) {
Integer foodPrice = (Integer) priceInfor.get
("價(jià)格");
if (foodPrice.equals
(childInputMoney_Ham)) {
System.out.println(" 您好,請(qǐng)收好
你的漢堡,歡迎下次光臨!");
} else {
System.out.println(" 對(duì)不起,你投
如的錢幣數(shù)量不夠,錢已經(jīng)如數(shù)歸還,請(qǐng)收好!");
}
} else if (foodName.equals("雞翅")) {
Integer foodPrice = (Integer) priceInfor.get
("價(jià)格");
if (foodPrice.equals
(childInputMoney_Chick)) {
System.out.println(" 您好,請(qǐng)收好
你的漢堡,歡迎下次光臨!");
} else {
System.out.println(" 對(duì)不起,你投
如的錢幣數(shù)量不夠,錢已經(jīng)如數(shù)歸還,請(qǐng)收好!");
}
}
}
}
?
通過(guò)上面的程序我們可以看出Mina的中業(yè)務(wù)邏輯處理都可以在IoHandler中,而不需要考慮對(duì)象的序列化和反序列化問(wèn)題。關(guān)于IoHandler的簡(jiǎn)單用法就說(shuō)這么多。下面再看看與IoHandler相關(guān)的幾個(gè)中要的類。
?
按照慣例,還是先給出IoHandler及其相關(guān)類的類圖:
從上面的類圖我們可以清晰的看到IoHandler是一個(gè)接口,它有兩個(gè)子類:
IoHandlerAdpater:它只是提供了IoHandler中定義的方法體,沒(méi)有任何的邏輯處理,你可以根據(jù)你自己的需求重寫(xiě)該類中的相關(guān)方法。這個(gè)類在實(shí)際的開(kāi)發(fā)中使用的是較多的。我們上面寫(xiě)的例子都是繼承于這個(gè)類來(lái)實(shí)現(xiàn)的。
SingleSessionIoHandlerDelegate:這是一個(gè)服務(wù)器和客戶端只有一個(gè)會(huì)話時(shí)使用的類,在該類的方法中沒(méi)有提供session的參數(shù),該類在實(shí)際的開(kāi)發(fā)中使用的較少,如果需要對(duì)該類進(jìn)行更深入的了解,請(qǐng)參考Mina 1.1.7的API文檔。
?
在Mina提供的IoHandler的具體實(shí)現(xiàn)中,大部分的實(shí)現(xiàn)類都是繼承與IoHandlerApater,IoHandlerAdpater在Mina 1.1.7中的子類有三個(gè):
ChainedIoHandler:這個(gè)類主要是用于處理IoHandler的messageReceived事件,它和IoHandlerChain配合使用。當(dāng)在業(yè)務(wù)邏輯中有多個(gè)IoHandler需要處理時(shí),你可以將你的每個(gè)IoHandler添加到IoHandlerChain中,這個(gè)和過(guò)濾器
鏈比較相似,關(guān)于IoFilter和IoHandlerChain的具體用法和區(qū)別會(huì)在后續(xù)的文檔中給出。
StreamIoHandler:該類也是用于處理IoHandler的messageReceived事件,它主要用于文件傳輸?shù)南到y(tǒng)中,比如FTP服務(wù)器中,如果需要對(duì)該類進(jìn)行更深入的了解,請(qǐng)參考Mina 1.1.7的API文檔。
DemuxingIoHandler:該類主要是用于處理多個(gè)IoHandler的messageReceived,由于在TCP/IP協(xié)議的數(shù)據(jù)傳輸中會(huì)出現(xiàn)數(shù)據(jù)的截?cái)喱F(xiàn)象(由于socket傳輸?shù)臄?shù)據(jù)包的長(zhǎng)度是固定的,當(dāng)數(shù)據(jù)包大于該長(zhǎng)度,數(shù)據(jù)包就會(huì)被截?cái)?,所以提供這個(gè)類主要是保證IoHandler所處理的數(shù)據(jù)包的完整性,這個(gè)和編解碼器中的CumulativeProtocolDecoder類似,關(guān)于這兩個(gè)類的具體介紹會(huì)在后續(xù)的文檔中給出。
?
至此,關(guān)于IoHandler的作用就講述完了,希望對(duì)你能有所幫助。:)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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