转自:http://blog.csdn.net/gaolingep/archive/2009/05/04/4147697.aspx
第一部分:mina各层的关系
图1.1
说明
-
IOService:
-
这个接口抽象了一切I/O操作,包括建立端口监听、I/O读写,
-
-
IOProcessor:
-
为IOService处理正真的I/O读写操作。 IOService在某端口监听,当发生int selected = select();时,说明有建立连接的客户端请求,IOService会调用IOProcessor,将session和交给processor处理。
-
IOProcessor也会有一个int selected = select(1000);的阻塞,等待IO事件。
-
当I/O事件到达后,会把输入读入到一个BUF中session.getChannel().read(buf.buf())(Java NIO) 。
-
-
IOFilter:
-
上面IOProcessor得到buf后,会交给 IOFilter处理,如果是读取IO则触发messageReceived 方法。
-
IOFilter一般被包含在一个IoFilterChain中,顾名思义,当然是实现了责任链模式的一根链条咯。
-
-
IoHandler :
-
是拿到 buf 做处理的一个接口,是用户最终会面对的一个接口。
-
上面的 IOFilter得到buf(以接收数据为例),IOFilter调用了IoHandler 的 messageReceived(s, message); 方法。
-
最后还要提一个接口:
IoSession :
A handle which represents connection between two end - points regardless of
transport types.
实际上这个接口是一个会话服务,或者它更像是一个大容器。后面我们还会讲到它。
第二部分:类图
2.1 IOService
-
IoAcceptor 接口:
服务器端接口,接受客户端访问的请求
-
AbstractIoService
设定处理函数、Filter、IoServiceListener 。
-
处理函数是一个Executor 或者是 Executor 的包装。
-
IoServiceListener 可以用于打印日志,主要有 Service 启动、停止、空闲等监听方法
-
-
AbstractIoAcceptor完成绑定监听端口
-
AbstractPollingIoAcceptor执行具体的监听连接以及监听I/O事件
-
NioSocketAcceptor用JAVA NIO的方式实现了具体的连接方法ServerSocketChannel ,例如 open , accept 等
2.2IoProcessor
显然,这个结构实现了组成模式
SimpleIoProcessorPool内有一个数组,包装了IoProcessor 。这个 SimpleIoProcessorPool的DEFAULT_SIZE 属性, 定义了开多少个IoProcessor 。
前面讲过 IoProcessor 为IOService处理正真的I/O读写操作。(在nio下,一个IoProcessor 可以在单线程中处理多个连接请求和 io 事件)除此之外,再开多个 IoProcessor ,一个 IoProcessor 启动一个线程。
2.3 IoSession
第三部分 源码解读
3.1初始化
SocketAcceptor acceptor = new NioSocketAcceptor();
在 图1.1中,我们看到, mina 会首先把请求交给 IOService。实际上,这个接口也是用户首先面对的接口。
-
用户在这个端口上执行setHandler (IoHandler handler) 方法。
-
并执行 IoAcceptor 接口的 bind (SocketAddress localAddress) 方法。
-
实例化SocketAcceptor ,会 super() 其父类的构造函数。
我们依次看看三个父类的构造函数
-
AbstractPollingIoAcceptor
protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
Classextends IoProcessor> processorClass) {
this (sessionConfig, null , new SimpleIoProcessorPool(processorClass),
true );
}
-
构造函数AbstractPollingIoAcceptor(new DefaultSocketSessionConfig(), NioProcessor.class); 定义了默认的 SessionConfig 和 NioProcessor 。
-
new SimpleIoProcessorPool(processorClass) 是把 NioProcessor 包装成了 pool. 看类图 IoProcessor 就很好理解了,这是一个组成模式。
-
AbstractIoAcceptor
protected AbstractIoAcceptor(IoSessionConfig sessionConfig, Executor executor) {
super (sessionConfig, executor);
defaultLocalAddresses .add( null );
}
AbstractIoAcceptor主要用来绑定监听端口。这个构造函数没有干其他的事情。
-
AbstractIoService
protected AbstractIoService(IoSessionConfig sessionConfig, Executor executor)
-
这个构造函数初始化 sessionConfig ,和当 executor 为空时,
if (executor == null ) {
System. out .println( "[GL:executor:]" +executor);
this . executor = Executors.newCachedThreadPool ();
createdExecutor = true ;
} else {
this . executor = executor;
createdExecutor = false ;
}
-
这个构造函数还有一个监听器,或者叫监听池(可以包含多个监听器)。用来监听 service 创建、连接、断开等动作,当上述动作发生地时候,会调用 listener 。里面可以写自己的一些方法。
3.2 初始化2
acceptor.setHandler( new EchoProtocolHandler());
设定处理函数, EchoProtocolHandler() 是用户自己编写的一个 handle ,看图 1.1 可以知道,这是 mina 平台处理的最后一步。 Mina 把请求经过 ioprocessor 处理器、多个 iofilter 过滤器 处理后,才会交给 EchoProtocolHandler 。
我们看看从 IOService到IoHandler 之间发生了什么
3.3运行
在main()函数中,我们看到一个方法
acceptor.bind( new InetSocketAddress( PORT ));
这一个 bind 方法,表面看只是一个端口绑定,实际上发生了很多有趣的事情。
IOService 类图告诉我们, bind 端口应该是 AbstractIoAcceptor 干的事情,去这个类中找。
-
AbstractIoAcceptor 类 bind 方法
// 端口打包成一个 list, 以实现多端口监听
List localAddresses = new ArrayList(1);
localAddresses.add(localAddress);
然后调用了子类 AbstractPollingIoAcceptor 的 bind0 方法
bind0(localAddressesCopy);
- AbstractPollingIoAcceptor. bind0 方法,把代码贴出来
protected final Set bind0(
Listextends SocketAddress> localAddresses) throws Exception {
// 这个 request 包装了 localAddresses ,间接包装了 localAddress
AcceptorOperationFuture request = new AcceptorOperationFuture(
localAddresses);
// adds the Registration request to the queue for the Workers
// to handle
registerQueue .add(request);
// creates the Acceptor instance and has the local
// executor kick it off.
/*
这个方法很重要,我们去看看发生了什么
*/
startupAcceptor();
// wakeup() 即 selector.wakeup();
wakeup();
//bind0 结束
- startupAcceptor(); 方法内部代码。需要注意的是 Acceptor 不是 IOACCEPTOR ,这个 Acceptor 是一个线程,用于处理 IO 事件。
if ( acceptor == null ) {
/*
Acceptor 完成 即监听连接事件 ,
如果有感兴趣的连接发生,即调用 processHandles(selectedHandles());
*/
acceptor = new Acceptor();
// 调用爷爷类 AbstractIoService 的方法。
// 把 acceptor 分配给线程池
executeWorker( acceptor );
}
- Acceptor ()代码
private class Acceptor implements Runnable {
public void run() {
int nHandles = 0;
while ( selectable ) { // 这个循环用来监听连接到达,以建立连接和 io 事件
try {
System. out .println( "[GaoLing:] 连接建立 " );
int selected = select(); // 如果一直没有新连接,则一直会阻塞
/*
* 这个方法完成:打开 ServerSocketChannel 通道,注册感兴趣的监听
将 ServerSocketChannel 丢到 boundHandles 中去
就是在定义的若干个端口放置监听事件,接受 accept
注意:只是建立监听而已!还没有建立客户端连接!!
for (SocketAddress a : localAddresses) {
/*
* 这个 open 函数会调用子类 NioSocketAcceptor 的 open 方法,
* 这个方法定义了一个通道,放置了一个感兴趣的 key:SelectionKey.OP_ACCEPT
* 由 selector 去监听
* 返回一个 ServerSocketChannel
*/
H handle = open(a);
open(a); 内部实现
ServerSocketChannel channel = ServerSocketChannel.open ();
channel.configureBlocking( false );
ServerSocket socket = channel.socket();
socket.bind(localAddress, getBacklog());
channel.register( selector , SelectionKey. OP_ACCEPT );
*/
nHandles += registerHandles();
// 如果有感兴趣的事件到达
if (selected > 0) {
// We have some connection request, let's process
// them here.
// processHandles(selectedHandles()); 是很重要的方法,一会我们看看发生了什么
// 开始调用 session ,
// 一旦有 IO in out 事件进来,调用这个函数。
// 这个函数有一个方法 session.getProcessor().add(session);
processHandles(selectedHandles());
}
。。。。。后面是回收处理,也很重要,但不在我们现在关注的范围内
} // 大 while 循环
- processHandles 代码
private void processHandles(Iterator handles) throws Exception {
// 注意这个 handles: 是 ServerSocketChannelIterator, 不是我们的 IoHandler !
while (handles.hasNext()) {
H handle = handles.next();
handles.remove();
/*
注意, session 出来了
* 参数 1 : processor 就是 SimpleIoProcessorPool 的实例 , 第一部分讲了来历,这里再提一下
* 在 AbstractPollingIoAcceptor 有构造函数
* protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
Class> processorClass) {
this(sessionConfig, null, new SimpleIoProcessorPool(processorClass) ,
true);
}
对 NioProcessor 进行了包装,成为 SimpleIoProcessorPool 。
* 参数 2 : handle 包装了 selector.selectedKeys()
* 调用子类 NioSocketAcceptor 的 accept 方法,
* 这个方法:
* SocketChannel client=server.accept();// 查找客户端套接字通道
* 初始化并返回 NioSocketSession 对象 return new NioSocketSession(this, processor, ch);
*/
T session = accept( processor , handle);
if (session == null ) {
break ;
}
// 这个方法比较复杂,不是我们今天讲得重点,先跳过去
//setAttributeMap
//setWriteRequestQueue
finishSessionInitialization(session, null , null );
// add the session to the SocketIoProcessor
// 完成了 session 和 process 的绑定,并开始处理 handle
//session.getProcessor() 返回 SimpleIoProcessorPool
// 这个方法开启了一个线程,调用了 AbstractPollingIoProcessor 的 add 方法
// 实际上上面我们说了, session.getProcessor() 得到的是 包装了 NioProcessor 对象的 SimpleIoProcessorPool , NioProcessor 对象间接继承了 add 方法
// 看看这个 add 方法,调用了 startupWorker(); ,开启了一个线程
session.getProcessor().add(session);
}
}
}
-
session.getProcessor().add(session); 方法
这个方法调用了 SimpleIoProcessorPool.add 。即引出了自定义线程池。参看类图 Processor。具体就跳过去了。
public final void add(T session) {
if (isDisposing()) {
throw new IllegalStateException( "Already disposed." );
}
// Adds the session to the newSession queue and starts the worker
newSessions .add(session);
startupWorker();
}
- startupWorker() 方法
private void startupWorker() {
synchronized ( lock ) {
// 这个 processor 不是 IOProcessor, 它只是一个线程,每隔 1s 种逐一通知 session
// 这个线程会一直轮询下去, for(;;)
if ( processor == null ) {
processor = new Processor();
// 注: session 已被加载到 newSessions.add(session); 中
executor .execute( new NamePreservingRunnable( processor , threadName ));
}
}
wakeup();
}
- Processor 方法
private class Processor implements Runnable {
public void run() {
。。。。。。。。
for (;;) {
try {
// 调用子类 NioProcessor 的 return selector.select(timeout);
int selected = select(1000);
if (selected > 0) { // 如果有连接过来,就调用 process 方法
process();
}
// 否则执行 "idle"
。。。。。。。。。。。。。。
- process(); 方法
private void process() throws Exception {
for (Iterator i = selectedSessions(); i.hasNext();) {
T session = i.next();
process(session);
i.remove();
}
}
- process(); 方法
private void process(T session) {
if (isReadable(session) && !session.isReadSuspended()) {
read(session);
}
if (isWritable(session) && !session.isWriteSuspended()) {
scheduleFlush(session);
}
}
快结束了
- read 方法
private void read(T session) {
IoSessionConfig config = session.getConfig();
//buf 存放了 channel.read 的结果
IoBuffer buf = IoBuffer.allocate (config.getReadBufferSize());
final boolean hasFragmentation =
session.getTransportMetadata().hasFragmentation();
try {
int readBytes = 0;
int ret;
// 初始化 buffer
。。。。。。
if (readBytes > 0) {
/ / session.getFilterChain(), 以前没有讲过 filterChain 是从哪里来的 ,但是提到过 session 是 NioSocketSession 的实例,这个类中定义了
//private final IoFilterChain filterChain = new DefaultIoFilterChain(this);
IoFilterChain filterChain = session.getFilterChain();
// 这句话包含了调用 handle ,把 buf 内容推送给它
//filterChain 是 DefaultIoFilterChain 的实例
// 在这个方法里面,会调用用户 handle 的方法!
filterChain.fireMessageReceived(buf);
buf = null ;
。。。。
}
- filetr 内的方法摘要
IoFilter filter = entry.getFilter();
//nextFilter 实例化了本类的 EntryImpl 的 内部类
NextFilter nextFilter = entry.getNextFilter();
// 这个 filter 会调用 IoFilterAdapter 的 messageReceived
filter.messageReceived(nextFilter, session,
message);
。。。
- 调用 handle 修成正果
session.getHandler().messageReceived(s, message);
3.4总结一下流程
- 3.4.1 初始化
实例化 SocketAcceptor 【 main 】 ->
完成 sessionConfig 、 IoProcessor 的初始化【 SocketAcceptor 父类】 ->
acceptor.setHandler 【 main 】
- 3.4.2 运行(对照类图看)
acceptor.bind( new InetSocketAddress( PORT )); 【 main 】 ->
AbstractIoAcceptor.bind 【 AbstractIoAcceptor 】 ->
AbstractPollingIoAcceptor. bind0 【 AbstractPollingIoAcceptor 】 ->
startupAcceptor() 【开线程,监听连接事件, AbstractPollingIoAcceptor 】 ->
class Acceptor 【 AbstractPollingIoAcceptor 】 ->
processHandles(Iterator handles) 【 AbstractPollingIoAcceptor 】 ->
T session = accept( processor , handle); 【初始化 session, AbstractPollingIoAcceptor 】 ->
session.getProcessor().add(session); 【处理 io 事件 ,AbstractPollingIoAcceptor 】 ->
SimpleIoProcessorPool.add 【这里用到了自定义线程池(数组), SimpleIoProcessorPool 】 ->
AbstractPollingIoProcessor.add 【调用 startupWorker() , AbstractPollingIoProcessor 】 ->
startupWorker(); 【处理 io 事件。 AbstractPollingIoProcessor 】 ->
processor = new Processor(); 【线程池,处理 IO 输入输出数据, AbstractPollingIoProcessor 】 ->
process() 【 AbstractPollingIoProcessor 】 ->
read(T session) 【 AbstractPollingIoProcessor 】 ->
filterChain->
handle