MINA是一个网络应用框架,在不牺牲性能和可扩展性的前提下用于解决如下问题:

1: 快速开发自己的英勇。

2:高可维护性,高可复用性:网络I/O编码,消息的编/解码,业务逻辑互相分离。

3:相对容易的进行单元测试。

 

3.1 IoFilters:

IoFilter为MINA的功能扩展提供了接口。它拦截所有的IO事件进行事件的预处理和后处理 (AOP)。我们可以把它想象成

Servlet的filters。

IoFilter能够实现以下几种目的:

事件日志

性能 检测

数据转换(e.g. SSL support),codec

防火墙…等等

3.2 codec: ProtocolCodecFactory

MINA提供了方便的Protocol支持。如上说讲,codec在 IoFilters中设置。

通过它的Encoder和Decoder,可以方便的扩展并支持各种基于Socket的网络协议,比如HTTP服务 器、FTP服务器、Telnet服务器等等。

要实现自己的编码/解码器(codec)只需要实现interface: ProtocolCodecFactory即可.

在MINA 1.0版本,MINA已经实现了几个常用的(codec factory):

DemuxingProtocolCodecFactory, 

NettyCodecFactory, 

ObjectSerializationCodecFactory, 

TextLineCodecFactory


其中: 

TextLineCodecFactory:

A ProtocolCodecFactory that performs encoding and decoding between a text line data and a Java 

string object. This codec is useful especially when you work with a text-based protocols such as SMTP and IMAP.

ObjectSerializationCodecFactory:

A ProtocolCodecFactory that serializes and deserializes Java objects. This codec is very useful when 

you have to prototype your application rapidly without any specific codec.

DemuxingProtocolCodecFactory:

A composite ProtocolCodecFactory that consists of multiple MessageEncoders and MessageDecoders. ProtocolEncoder

and ProtocolDecoder this factory returns demultiplex incoming messages and buffers to appropriate MessageEncoders 

and MessageDecoders.

NettyCodecFactory:

A MINA ProtocolCodecFactory that provides encoder and decoder for Netty2 Messages and MessageRecognizers.

3.3 business logic: IoHandler

MINA中,所有的业务逻辑都有实现了IoHandler的class完成

interfaceHandles:

all protocol events fired by MINA. There are 6 event handler methods, and they are all invoked by MINA automatically. 

当事件发生时,将触发IoHandler中的方 法:

sessionCreated, sessionOpened, sessionClosed, sessionIdle, exceptionCaught, messageReceived, messageSent

MINA 1.O中,IoHandler的实现类:

ChainedIoHandler, DemuxingIoHandler, IoHandlerAdapter, SingleSessionIoHandlerDelegate, StreamIoHandler 

具体 细节可参考javadoc。

3.4   MINA的高级主题:线程模式

MINA通过它灵活的filter机制来提供多种线程模型。

没有线程池过滤器被使用时 MINA运行在一个单线程模式。

如果添加了一个IoThreadPoolFilter到IoAcceptor,将得到一个leader- follower模式的线程池。

如果再添加一个ProtocolThreadPoolFilter,server将有两个线程池;

一个 (IoThreadPoolFilter)被用于对message对象进行转换,另外一个(ProtocolThreadPoolFilter)被用于处 理业务逻辑。 

SimpleServiceRegistry加上IoThreadPoolFilter和 ProtocolThreadPoolFilter的缺省实现即可适用于需

要高伸缩性的应用。如果想使用自己的线程模型,请参考 SimpleServiceRegistry的源代码,并且自己

初始化Acceptor。

IoThreadPoolFilter threadPool = new IoThreadPoolFilter();threadPool.start();

IoAcceptor acceptor = new SocketAcceptor();

acceptor.getFilterChain().addLast( "threadPool", threadPool);

ProtocolThreadPoolFilter threadPool2 = new ProtocolThreadPoolFilter();

threadPool2.start();

ProtocolAcceptor acceptor2 = new IoProtocolAcceptor( acceptor );

acceptor2.getFilterChain().addLast( "threadPool", threadPool2 );

...

threadPool2.stop();

threadPool.stop();

采用MINA进行socket开发,一般步骤如下:

1:

server:

IoAcceptor acceptor = new SocketAcceptor(); //建立client接收器

or client:

SocketConnector connector = new SocketConnector();  //建立一个连接器

2:server的属性配置:

SocketAcceptorConfig cfg = new SocketAcceptorConfig();

cfg.setReuseAddress(true);

cfg.getFilterChain().addLast(

"codec",

new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) ); //对象序列化 codec factory

cfg.getFilterChain().addLast( "logger", new LoggingFilter() );

3:绑定 address和business logic

server:

acceptor.bind(

new InetSocketAddress( SERVER_PORT ),

new ServerSessionHandler( ), cfg ); // 绑定address和handler

client:

connector.connect(new InetSocketAddress( HOSTNAME, PORT ),

new ClientSessionHandler(msg), cfg );

下面的这个简单的example演示client和server传递object的过程:

Message.java

public class Message implements Serializable {

    private int type;

private int status;

private String msgBody;


public Message(int type, int status, String msgBody) 

{

this.type = type;

this.status = status;

this.msgBody = msgBody;

}

    public String getMsgBody() {

return msgBody;

}

    public void setMsgBody(String msgBody) {

this.msgBody = msgBody;

}

    public int getStatus() {

return status;

}

    public void setStatus(int status) {

this.status = status;

}

    public int getType() {

return type;

}

    public void setType(int type) {

this.type = type;

}

}

Client.java

public class Client

{

private static final String HOSTNAME = "localhost";

private static final int PORT = 8080;

private static final int CONNECT_TIMEOUT = 30; // seconds

public static void main( String[] args ) throws Throwable

{

SocketConnector connector = new SocketConnector();        

// Configure the service.

SocketConnectorConfig cfg = new SocketConnectorConfig();

cfg.setConnectTimeout( CONNECT_TIMEOUT );

cfg.getFilterChain().addLast(

"codec",

new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) );

        cfg.getFilterChain().addLast( "logger", new LoggingFilter() );


IoSession session; 

Message msg = new Message(0,1,"hello");

connector.connect(new InetSocketAddress( HOSTNAME, PORT ),

new ClientSessionHandler(msg), cfg );

    }

}

ClientSessionHandler.java

public class ClientSessionHandler extends IoHandlerAdapter

{

private Object msg;


public ClientSessionHandler(Object msg) 

{

this.msg = msg;

}

public void sessionOpened( IoSession session )

{

session.write(this.msg);

}

    public void messageReceived( IoSession session, Object message )

{

System.out.println("in messageReceived!");

Message rm = (Message ) message;        

SessionLog.debug(session, rm.getMsgBody());

System.out.println("message is: " + rm.getMsgBody());

session.write(rm);

}

    public void exceptionCaught( IoSession session, Throwable cause )

{

session.close();

}

}

Server.java

public class Server

{

private static final int SERVER_PORT = 8080;

    public static void main( String[] args ) throws Throwable

{

IoAcceptor acceptor = new SocketAcceptor();


// Prepare the service configuration. 

SocketAcceptorConfig cfg = new SocketAcceptorConfig();

cfg.setReuseAddress( true );

        cfg.getFilterChain().addLast(

"codec",

new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) );

cfg.getFilterChain().addLast( "logger", new LoggingFilter() );

        acceptor.bind(

new InetSocketAddress( SERVER_PORT ),

new ServerSessionHandler( ), cfg );

        System.out.println( "The server Listening on port " + SERVER_PORT );

}

}

ServerSessionHandler.java

public class ServerSessionHandler extends IoHandlerAdapter

{

public void sessionOpened( IoSession session )

{

// set idle time to 60 seconds

session.setIdleTime( IdleStatus.BOTH_IDLE, 60 );

session.setAttribute("times",new Integer(0));

}

    public void messageReceived( IoSession session, Object message )

{

System.out.println("in messageReceived");

int times = ((Integer)(session.getAttribute("times"))).intValue();

System.out.println("tiems = " + times);

// communicate 30 times,then close the session.

if (times < 30)

{

times++;

session.setAttribute("times", new Integer(times));           

Message msg;

msg = (Message) message;

msg.setMsgBody("in server side: " + msg.getMsgBody()); 

System.out.println("begin send msg: " + msg.getMsgBody());

session.write(msg);

}

else

{

session.close();

}

}

    public void sessionIdle( IoSession session, IdleStatus status )

{

SessionLog.info( session, "Disconnecting the idle." );

// disconnect an idle client

session.close();

}

    public void exceptionCaught( IoSession session, Throwable cause )

{

// close the connection on exceptional situation

session.close();

}

}

MINA自己附带的Demo已经很好的说明了它的运用。

值得一提的是它 的SumUp:客户端发送几个数字,服务端求和后并返回结果。这个简单的程序演示了如何自己实现CODEC。

补充提示:

下载并运行MINA的demo程序还颇非周折:

运行MINA demo appli擦tion:

1:在JDK5

产 生错误:

Exception in thread "main" java.lang.NoClassDefFoundError: edu/emory/mathcs/backport/java/util/concurrent/Executor

at org.apache.mina.example.reverser.Main.main(Main.java:44)


察看mina的 QA email: 

http://www.mail-archive.com/mina-dev@directory.apache.org/msg02252.html

原来需要下载:backport-util-concurrent.jar并加入classpath

http://dcl.mathcs.emory.edu/util/backport-util-concurrent/

继续运行还是报错:

Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

原来MINA采用了slf4j项目作为log,继续下载

slf4j-simple.jar等,并加入classpath:

http://www.slf4j.org/download.html