终于又有时间和精力来写写东西啦,真开心~
这两天闲来没事翻了翻Mina的源码,小有感触,于是决定简单分享一下。
从服务端出发来分析一下吧。Mina有这么几个核心的接口类:
IoAcceptor: 启动server段监听,启动Acceptor线程,处理连接请求同时生成IoSession并放到一个数组里面。
IoProcessor: 启动Processor线程。循环处理上面提到的数组里面的IoSession. 该读读,该写写。
IoSession: 客户端和服务端的会话抽象
IoFilter: Mina用来处理消息的节点链中的节点
IoHander: Mina事件监听类。通常也是客户化开发需要扩展的基础接口。
闲言少叙,上一张自己画的sequence 图。因为是第一次画这种图,如有不妥请童鞋们指正~
哈哈通过这张图,什么Nio啊,异步什么的就比较能够明显看出来了。
至于NIO,在NioAcceptor里面,对连接请求的处理是通过Selector来实现的。具体可参考java NIO.
至于异步,可以发现,实际上的读写都是最终通过Processor来实现的。客户端的读写都是放到一个队列里面,
Processor 不断loop以完成对队列读写的实际操作并且在完成时设置FutureOperation的标志位。
还有一些细节的东西,比如Acceptor是只有一个线程,而Processor是有多个线程的。默认情况下Processor的线程数是
主机CPU个数+1 。
这个的原理是:
为了以下描述的清晰性,先贴一下Demo 代码,以方便以下的分析:
public static void main(String[] args) throws Exception {
SocketAcceptor acceptor = new NioSocketAcceptor();
acceptor.setReuseAddress( true );
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
// Add SSL filter if SSL is enabled.
if (USE_SSL) {
addSSLSupport(chain);
}
// Bind
acceptor.setHandler(new EchoProtocolHandler());
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("Listening on port " + PORT);
for (;;) {
System.out.println("R: " + acceptor.getStatistics().getReadBytesThroughput() +
", W: " + acceptor.getStatistics().getWrittenBytesThroughput());
Thread.sleep(3000);
}
}
在AbstracePoolingIoAcceptor构造的时候,传入的processor 是一个SimpleIoProcessorPool的实例,这个类的作用就是维护一个默认CPU+1数量的IoProcessor池。入口如下:
protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
Class<? extends IoProcessor<T>> processorClass) {
this(sessionConfig, null, new SimpleIoProcessorPool<T>(processorClass),
true);
}
private static final int DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1;
public SimpleIoProcessorPool(Class<? extends IoProcessor<T>> processorType) {
this(processorType, null, DEFAULT_SIZE);
}
每次调用IoProccesor(在我们的例子里面是SimpleIoProcessorPool)的add方法的时候,会随机从IoProcessor池里面取一个实例然后与要add的session关联。于是实际调用的就是NioProcessor的add方法. 通过这种方式,每个被调用过的IoProcessor都会启动一个自己的Processor线程。
贴一下为add过程的源码:
SimpleIoProcessorPool 类
public final void add(T session) {
getProcessor(session).add(session);
}
private IoProcessor<T> getProcessor(T session) {
IoProcessor<T> processor = (IoProcessor<T>) session.getAttribute(PROCESSOR);
if (processor == null) {
processor = nextProcessor(session);
session.setAttributeIfAbsent(PROCESSOR, processor);
}
return processor;
}
private IoProcessor<T> nextProcessor(T session) {
if (disposed) {
throw new IllegalStateException(
"A disposed processor cannot be accessed.");
}
return pool[Math.abs((int)session.getId()) % pool.length];
}
通过代码很清晰的能够看到, 实际上的add 调用还是NioProcessor的 add 调用。