淺談Java的Mina框架傳遞對象
接觸java的Mina框架已經(jīng)有很多時間了,在網(wǎng)上也讀過了很多的相關(guān)文章,發(fā)現(xiàn)Mina框架的確是一個值得拿來好好研究的東西,前些日子寫了一個山寨QQ項目,其中的通信部分用到了java中自帶的InputStream,OutputStream,Writer,Reader等等,感覺其中的很大的一個問題就是難以將事務(wù)處理的邏輯層與解析層分離開來,造成整個項目看起來比較臃腫,繁瑣,不夠模塊化,接觸Mina后發(fā)現(xiàn)mina在這方面做的很是恰到好處。
看到文章標(biāo)題,你或許會有一些疑惑:
1、Mina框架傳遞對象是怎么回事
2、Mina傳遞對象可以用來做什么
3、Mina傳遞對象是怎么進(jìn)行的
4、Mina傳遞對象過程中會遇到什么問題呢
在用原來的java的InputStream,OutputStream,Writer,Reader等進(jìn)行通信的時候我們會將信息編碼轉(zhuǎn)化成字節(jié)流等進(jìn)行信息傳遞,InputStream,OutputStream是基于字節(jié)流的,而Writer,Reader是基于字符的,我們都知道進(jìn)行通信的服務(wù)器和客戶端是事先必須定好通信協(xié)議,如果我們將
這是我們會自然的想到要用一種東西將各個格式的信息進(jìn)行分類統(tǒng)一起來并方便進(jìn)行一些必要的信息處理,為符合這些特點,我們會想到類這個東東恰恰滿足了這些性質(zhì),我們可以將信息的格式中的內(nèi)容定義為類的屬性,而對這些屬性的處理就可以用類中的方法來予以解決,這樣就對信息進(jìn)行了很好的包裝。
這種思想有了,那就是在通信的時候直接進(jìn)行形式上的對象傳遞(實際上在通信的時候都是最終以字節(jié)流的方式進(jìn)行傳遞的),那么我們就要找一種工具進(jìn)行這種形式的信息傳遞,對了,這種工具就是Mina框架,我們只看他其中的一個方法
public void messageReceived(IoSession session, Object message),這是進(jìn)行消息接收是能夠被 觸發(fā)的一個方法,參數(shù)session代表當(dāng)前的會話對象,參數(shù)message代表接收的到的信息,這時您會發(fā)現(xiàn)message的類型是Object型,而類 Object 是類層次結(jié)構(gòu)的根類,當(dāng)然可以用對象型的作為message啦!前面提到通信的時候都是最終以字節(jié)流的方式進(jìn)行傳遞的,這樣就要進(jìn)行:對象(客戶端)->字節(jié)流(客戶端)->發(fā)送->接收->字節(jié)流(服務(wù)器)->對象(服務(wù)器)的過程,呵呵不用擔(dān)心,這些繁瑣的過程,Mina都提供了很好的底層默認(rèn)實現(xiàn)所以你只需稍稍敲點代碼就行了。
光說不練還是不行,先上一個程序?qū)嵗?/P>
服務(wù)器端(1):
Java代碼
- package Mina.server;
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
- import org.apache.mina.filter.codec.ProtocolCodecFilter;
- import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
- import org.apache.mina.transport.socket.SocketAcceptor;
- import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
- public class MainServer {
- private static MainServer mainServer = null;
- private SocketAcceptor acceptor = new NioSocketAcceptor();
- private DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
- private int bindPort = 8888;
- public static MainServer getInstances() {
- if (null == mainServer) {
- mainServer = new MainServer();
- }
- return mainServer;
- }
- private MainServer() {
- chain.addLast("myChin", new ProtocolCodecFilter(
- new ObjectSerializationCodecFactory()));
- acceptor.setHandler(ServerHandler.getInstances());
- try {
- acceptor.bind(new InetSocketAddress(bindPort));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) throws Exception {
- MainServer.getInstances();
- }
- }
服務(wù)器端(2):
Java代碼
- package Mina.server;
- import org.apache.mina.core.filterchain.IoFilterAdapter;
- import org.apache.mina.core.service.IoHandler;
- import org.apache.mina.core.session.IdleStatus;
- import org.apache.mina.core.session.IoSession;
- import Mina.Object.UserInfo;
- public class ServerHandler extends IoFilterAdapter implements IoHandler {
- private static ServerHandler samplMinaServerHandler = null;
- public static ServerHandler getInstances() {
- if (null == samplMinaServerHandler) {
- samplMinaServerHandler = new ServerHandler();
- }
- return samplMinaServerHandler;
- }
- private ServerHandler() {
- }
- // 當(dāng)連接后打開時觸發(fā)此方法,一般此方法與 sessionCreated 會被同時觸發(fā)
- public void sessionOpened(IoSession session) throws Exception {
- }
- public void sessionClosed(IoSession session) {
- }
- public void messageReceived(IoSession session, Object message)
- throws Exception {
- if (message instanceof UserInfo) {
- UserInfo text = (UserInfo) message;
- System.out.println("服務(wù)器接收到從客戶端的姓名:"+text.getName());
- System.out.println("服務(wù)器接收到從客戶端的QQ:"+text.getQQNum());
- }
- }
- public void exceptionCaught(IoSession arg0, Throwable arg1)
- throws Exception {
- }
- // 當(dāng)消息傳送到客戶端后觸發(fā)
- public void messageSent(IoSession arg0, Object arg1) throws Exception {
- }
- // 當(dāng)一個新客戶端連接后觸發(fā)此方法.
- public void sessionCreated(IoSession arg0) throws Exception {
- }
- // 當(dāng)連接空閑時觸發(fā)此方法.
- public void sessionIdle(IoSession arg0, IdleStatus arg1) throws Exception {
- }
- }
客戶端(1):
Java代碼
- package Mina.client;
- import java.net.InetSocketAddress;
- import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
- import org.apache.mina.core.future.ConnectFuture;
- import org.apache.mina.filter.codec.ProtocolCodecFilter;
- import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
- import org.apache.mina.transport.socket.nio.NioSocketConnector;
- public class MainClient {
- private static MainClient mainClient = null;
- NioSocketConnector connector = new NioSocketConnector();
- DefaultIoFilterChainBuilder chain = connector.getFilterChain();
- public static MainClient getInstances() {
- if (null == mainClient) {
- mainClient = new MainClient();
- }
- return mainClient;
- }
- private MainClient() {
- chain.addLast("myChin", new ProtocolCodecFilter(
- new ObjectSerializationCodecFactory()));
- connector.setHandler(ClientHandler.getInstances());
- connector.setConnectTimeout(30);
- ConnectFuture cf = connector.connect(new InetSocketAddress("localhost",
- 8888));
- }
- public static void main(String args[]) {
- MainClient.getInstances();
- }
- }
客戶端(2):
Java代碼

- package Mina.client;
- import org.apache.mina.core.service.IoHandlerAdapter;
- import org.apache.mina.core.session.IoSession;
- import Mina.Object.UserInfo;
- public class ClientHandler extends IoHandlerAdapter {
- private static ClientHandler samplMinaClientHandler = null;
- public static ClientHandler getInstances() {
- if (null == samplMinaClientHandler) {
- samplMinaClientHandler = new ClientHandler();
- }
- return samplMinaClientHandler;
- }
- private ClientHandler() {
- }
- public void sessionOpened(IoSession session) throws Exception {
- session.write("客戶端與服務(wù)器的會話打開了……");
- UserInfo text=new UserInfo();
- text.setName("梅竹寒香");
- text.setQQNum("972341215");
- session.write(text);
- }
- public void sessionClosed(IoSession session) {
- }
- public void messageReceived(IoSession session, Object message)
- throws Exception {
- }
- public void messageSent(IoSession arg0, Object arg1) throws Exception {
- System.out.println("客戶端已經(jīng)向服務(wù)器發(fā)送了:"+(String)arg1);
- }
- }
公共類:
Java代碼

- package Mina.Object;
- public class UserInfo implements java.io.Serializable{
- private String name;
- private String QQNum;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getQQNum() {
- return QQNum;
- }
- public void setQQNum(String qQNum) {
- QQNum = qQNum;
- }
- }
如下建包即可:

以上就是對象的收發(fā)的簡單示例,如果報錯,或許會是一下原因:1、包的引進(jìn)是否妥當(dāng) 2、是否引入了mina的第三方包(網(wǎng)上有了很多的相關(guān)文章,在此就不在贅述了)
通過程序您會看到對象已經(jīng)成功傳遞并進(jìn)行了相關(guān)屬性的輸出,對于這個簡單的程序我稍做些相關(guān)說明:
1、進(jìn)行傳遞的對象所實例化的類要實現(xiàn)java.io.Serializable序列化接口
2、您會發(fā)現(xiàn)實例中的類尤其是相關(guān)的IoHandlerAdapter繼承類都采用了單實例模式,為什么這樣做呢,原因很簡單,那就是要在整個通信過程中做到對象session的等實例的單一防止發(fā)生“所托非人”的現(xiàn)象
3、服務(wù)器接收到message在進(jìn)行類判斷時用了instanceof關(guān)鍵字
如果你看到上面的實例就覺得對象傳遞的學(xué)習(xí)已經(jīng)成功了,那就錯了,細(xì)心的博友看到這個包結(jié)構(gòu):

是不是有點問題呢。
例如客戶端傳了一個userinfo對象到服務(wù)器,在服務(wù)器端判斷如果是userinfo對象后就打印出相關(guān)信息,我看源碼文檔其中有這樣的建包方式

其中服務(wù)器和客戶端共用了中間的Mina.Object包,這樣在收到對象后就能通過instanceof關(guān)鍵字判斷是不是useinfo對象,我看了一下,這個方法是可行的,現(xiàn)在的問題是,我們?nèi)绻帉懲ㄓ嵻浖臅r候,肯定是服務(wù)器和客戶端是要分開的,所以那個Mina.Object包是不能共享的,所以問題來了(1)、如果將userinfo放到客戶端中,那么該怎么用instanceof進(jìn)行判斷是不是userinfo呢(這時你已經(jīng)不能再引入服務(wù)器中的userinfo了)(2)、如果在客戶端和服務(wù)器中都編寫一個類定義一樣的userinfo,可是他們這兩個類是分屬不同的包,所以是兩個不同的類了,這樣在用instanceof進(jìn)行判斷的時候也是行不通的;那么我們該用什么方法來進(jìn)行判斷接收到的類是不是userinfo對象呢?
這個問題把我糾結(jié)了很久,在網(wǎng)上面搜了好久也沒有解決,最后想了想那個(2)或許可以改動改動就可以解決,問題的關(guān)鍵在于兩個UserInfo分屬于兩個不同的包,如果可以將包名一致就好了,但是在一個工程里面不能同時建立兩個命名一樣的包,這樣你就會發(fā)現(xiàn)何不建立兩個工程呢一個是服務(wù)器,一個是客戶端,這樣都可以分別建立名字都是Object的包,這樣可不可行呢,經(jīng)過試驗果然可以,這樣就就解決了上面的問題工程圖如下

好啦,有了這個工具,您會有什么想法呢?對象傳遞還可以做什么?那就是可以用它來進(jìn)行圖片,文件的傳遞啦,這個只是個小小的提示具體怎么實現(xiàn),就要看各位博友怎么發(fā)揮啦!呵呵
【編輯推薦】