Apache MINA(Multipurpose Infrastructure for Network Applications)是一个网络应用程序框架,用来帮助用户简单地开发高性能和高可靠性的网络应用程序。它提供了一个通过Java NIO在不同的传输例如TCP/IP和UDP/IP上抽象的事件驱动的异步API。
服务端的处理过程:一个请求,处理他们,发送返回
mina一个服务的创建过程及客户端接收返回
一.创建一个服务
IoAcceptor acceptor = new NioSocketAcceptor();
找到对应构造函数
public NioSocketAcceptor() {
super(new DefaultSocketSessionConfig(), NioProcessor.class);
((DefaultSocketSessionConfig) getSessionConfig()).init(this);
}
1.super(new DefaultSocketSessionConfig(), NioProcessor.class);
其先构造对应父类:
protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
Class<? extends IoProcessor<S>> processorClass) {
this(sessionConfig, null, new SimpleIoProcessorPool<S>(processorClass),
true);
}
SimpleIoProcessorPool创建NioProcessor线程池并创建多个处理器
// Create the executor if none is provided
createdExecutor = (executor == null);
if (createdExecutor) {
this.executor = Executors.newCachedThreadPool();//创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
} else {
this.executor = executor;
}
pool = new IoProcessor[size];
线程池的最佳大小取决于可用处理器的数目以及工作队列中的任务的性质。若在一个具有 N 个处理器的系统上只有一个工作队列,其中全部是计算性质的任务,在线程池具有 N 或 N+1 个线程时一般会获得最大的 CPU 利用率。
其中pool = new IoProcessor[size];创建多个处理器,最大使用cpu利用率。size大小就是获取JVM处理任务数:
private static final int DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1;
其中mina是用Reactor模式或者说是Observer模式 来实现 Reactor模式可参考:http://www.cnblogs.com/alipayhutu/archive/2012/05/04/2483018.html http://woming66.iteye.com/blog/1189748 http://wiki.jerrypeng.me/io-multiplexing-reactor.html
/**
*
* Creates a new instance of NioProcessor.
*
* @param executor
*/
public NioProcessor(Executor executor) {
super(executor);
try {
// Open a new selector
selector = Selector.open();//静态方法,创建一个selector实例
} catch (IOException e) {
throw new RuntimeIoException("Failed to open a selector.", e);
}
}
其中处理session对应不同的处理器(在加入session调用到)
private IoProcessor<S> getProcessor(S session) {
IoProcessor<S> processor = (IoProcessor<S>) session.getAttribute(PROCESSOR);
if (processor == null) {
if (disposed || disposing) {
throw new IllegalStateException("A disposed processor cannot be accessed.");
}
processor =pool[Math.abs((int) session.getId()) % pool.length];//随机获取NioProcessor
if (processor == null) {
throw new IllegalStateException("A disposed processor cannot be accessed.");
}
session.setAttributeIfAbsent(PROCESSOR, processor);
}
return processor;
}
接受创建一个session都会初始化,后面会提及
@Override
protected void init(NioSession session) throws Exception {
SelectableChannel ch = (SelectableChannel) session.getChannel();
ch.configureBlocking(false);
session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ,
session));//这里注册读模式,以便业务读取处理 在socket接收设置为OP_ACCEPT
}
这就是典型的Ractor模式,处理Nio非阻塞应用。
在AbstractPollingIoAcceptor类调用init();
// Initialize the selector
init();
// The selector is now ready, we can switch the
// flag to true so that incoming connection can be accepted
selectable = true;//在Acceptor中while循环等待客户端请求,下文会提及
调用NioSocketAcceptor的init方法:
protected void init() throws Exception {
selector = Selector.open();//这是处理Nio请求,在启动监听会监听处理
}
这里又用到了Reactor模式,不知道这个模式可以先去了解了解
还做了一些创建一个监听
// Create the listeners, and add a first listener : a activation listener
// for this service, which will give information on the service state.
listeners = new IoServiceListenerSupport(this);
其它一些参数初始化
2.((DefaultSocketSessionConfig) getSessionConfig()).init(this);把NioSocketAcceptor初始化到Ioservice接口
acceptor.bind(new InetSocketAddress(9999));
AbstractIoAcceptor类调用AbstractPollingIoAcceptor类中bindInternal方法
Set<SocketAddress> addresses = bindInternal( localAddressesCopy );
getListeners().fireServiceActivated();//获取监听
protected final Set<SocketAddress> bindInternal(
List<? extends SocketAddress> localAddresses) throws Exception {
// Create a bind request as a Future operation. When the selector
// have handled the registration, it will signal this future.每次要新绑定一个端口
AcceptorOperationFuture request = new AcceptorOperationFuture(
localAddresses);
// adds the Registration request to the queue for the Workers to handle
// 增加一个register动作,在工作者线程中处理
registerQueue.add(request);
// creates the Acceptor instance and has the local
// executor kick it off.
startupAcceptor();//启动工作者线程
// As we just started the acceptor, we have to unblock the select()
// in order to process the bind request we just have added to the
// registerQueue.
wakeup();//唤醒select状态
// Now, we wait until this request is completed.
request.awaitUninterruptibly();//堵塞直至监听成功
if (request.getException() != null) {
throw request.getException();
}
// Update the local addresses.
// setLocalAddresses() shouldn't be called from the worker thread
// because of deadlock.
Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();
for (H handle:boundHandles.values()) {
newLocalAddresses.add(localAddress(handle));
}
return newLocalAddresses;
}
1.startupAcceptor();//启动工作者线程
// start the acceptor if not already started
Acceptor acceptor = acceptorRef.get();
if (acceptor == null) {
acceptor = new Acceptor();//原子变量
if (acceptorRef.compareAndSet(null, acceptor)) {
executeWorker(acceptor);//启动工作线程池处理
}
其中原子变量可以学习学习AtomicReference、AtomicLong、AtomicInteger、AtomicBoolean可以查看Api进行学习
1.1 创建一个Acceptor线程,接收客户端的请求
while (selectable) {
try {
// Detect if we have some keys ready to be processed
// The select() will be woke up if some new connection
// have occurred, or if the selector has been explicitly
// woke up
int selected = select();//接收客户端请求
// this actually sets the selector to OP_ACCEPT,
// and binds to the port on which this class will
// listen on
nHandles += registerHandles();//注册启动监听
.....
if (selected > 0) {
// We have some connection request, let's process
// them here.
processHandles(selectedHandles());//从这些key中的channel()方法中取连接请求注册的channel,进行处理
}
// check to see if any cancellation request has been made.
nHandles -= unregisterHandles();
1.1.1registerHandles();中调用open(a);
// Process all the addresses
for (SocketAddress a : localAddresses) {
H handle = open(a);
newHandles.put(localAddress(handle), handle);
}
这里可以看看Reactor模式,就会更容易理解
protected ServerSocketChannel open(SocketAddress localAddress)
throws Exception {
// Creates the listening ServerSocket
ServerSocketChannel channel = ServerSocketChannel.open();//新建NIO通道,监听端口
boolean success = false;
try {
// This is a non blocking socket channel
channel.configureBlocking(false);//设置为非阻塞状态
// Configure the server socket,
ServerSocket socket = channel.socket();
// Set the reuseAddress flag accordingly with the setting
socket.setReuseAddress(isReuseAddress());
// and bind.
socket.bind(localAddress, getBacklog());
// Register the channel within the selector for ACCEPT event
channel.register(selector, SelectionKey.OP_ACCEPT);//NIO通道选绑定到择器selector 设置为接收,在处理器中设置为读取
success = true;
} finally {
if (!success) {
close(channel);
}
}
return channel;
}
二.接收一个客户端请求
1 当一个请求过来是,才执行processHandles(selectedHandles());//从这些key中的channel()方法中取连接请求注册的channel,进行处理
private void processHandles(Iterator<H> handles) throws Exception {
while (handles.hasNext()) {
H handle = handles.next();
handles.remove();//移除处理的请求
// Associates a new created connection to a processor,
// and get back a session
S session = accept(processor, handle);//获取客户端连接并创建一个NIoSession
if (session == null) {
break;
}
initSession(session, null, null);//初始化一些session参数 把sesssion加入IoSessionDataStructureFactory,以便为Ioservice提供新的会话数据
// add the session to the SocketIoProcessor
session.getProcessor().add(session);//加入处理器
}
}
session.getProcessor随机获取处理器(可参考上文的getProcessor(S session)方法)
1.1 accept(processor, handle);这里并创建默认过滤器DefaultIoFilterChain 过滤器可以看这篇文章http://www.iteye.com/topic/1124504
return new NioSocketSession(this, processor, ch);
protected NioSession(IoProcessor<NioSession> processor, IoService service, Channel channel) {
super(service);
this.channel = channel;
this.processor = processor;
filterChain = new DefaultIoFilterChain(this);//创建默认过滤器DefaultIoFilterChain
}
1.2 session.getProcessor().add(session);//加入处理器
public final void add(S session) {
if (disposed || disposing) {
throw new IllegalStateException("Already disposed.");
}
// Adds the session to the newSession queue and starts the worker
newSessions.add(session);
startupProcessor();
}
1.2.1 startupProcessor();启动处理器
private void startupProcessor() {
Processor processor = processorRef.get();
if (processor == null) {
processor = new Processor();
if (processorRef.compareAndSet(null, processor)) {
executor.execute(new NamePreservingRunnable(processor, threadName));//放入线程池
}
}
// Just stop the select() and start it again, so that the processor
// can be activated immediately.
wakeup();
}
Processor与Acceptor线程类似 run方法部分代码
// Manage newly created session first
nSessions += handleNewSessions();//创建管理新的session
updateTrafficMask();
// Now, if we have had some incoming or outgoing events,
// deal with them
if (selected > 0) {
//LOG.debug("Processing ..."); // This log hurts one of the MDCFilter test...
process();//处理创建的seesion请求
}
handleNewSessions();
private int handleNewSessions() {
int addedSessions = 0;
for (S session = newSessions.poll(); session != null; session = newSessions.poll()) {
if (addNow(session)) {//增加管理session
// A new session has been created
addedSessions++;
}
}
return addedSessions;
}
addNow(session)中
init(session);
registered = true;
// Build the filter chain of this session.
IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder();//获取过滤器
chainBuilder.buildFilterChain(session.getFilterChain());
// DefaultIoFilterChain.CONNECT_FUTURE is cleared inside here
// in AbstractIoFilterChain.fireSessionOpened().
// Propagate the SESSION_CREATED event up to the chain
IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners();
listeners.fireSessionCreated(session);//触发seesionCreated事件,进入过滤器处理
接受创建一个session都会初始化
@Override
protected void init(NioSession session) throws Exception {
SelectableChannel ch = (SelectableChannel) session.getChannel();
ch.configureBlocking(false);
session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ,
session));//这里注册读模式,以便业务读取处理 在socket接收设置为OP_ACCEPT
}
process();//处理创建的seesion请求
/**
* Deal with session ready for the read or write operations, or both.
*/
private void process(S session) {
// Process Reads //根据key来判断读写
if (isReadable(session) && !session.isReadSuspended()) {
read(session);//读取session
}
// Process writes
if (isWritable(session) && !session.isWriteSuspended()) {
// add the session to the queue, if it's not already there
if (session.setScheduledForFlush(true)) {
flushingSessions.add(session);
}
}
}
read(session);最终调用触发fireMessageReceived进入业务处理,进入handler处理
IoFilterChain filterChain = session.getFilterChain();
filterChain.fireMessageReceived(buf);
二.服务端返回数据
在handler里使用session.write时
public WriteFuture write(Object message) {
return write(message, null);
}
在write(Object message, SocketAddress remoteAddress)方法中
// Then, get the chain and inject the WriteRequest into it
IoFilterChain filterChain = getFilterChain();
filterChain.fireFilterWrite(writeRequest);//触发事件进入过滤器
public void fireFilterWrite(WriteRequest writeRequest) {
Entry tail = this.tail;//过滤器,原路返回
callPreviousFilterWrite(tail, session, writeRequest);
}
private void callPreviousFilterWrite(Entry entry, IoSession session,
WriteRequest writeRequest) {
try {
IoFilter filter = entry.getFilter();
NextFilter nextFilter = entry.getNextFilter();
filter.filterWrite(nextFilter, session, writeRequest);
} catch (Throwable e) {
writeRequest.getFuture().setException(e);
fireExceptionCaught(e);
}
}
经过过滤器,返回给客户端。
个人总结:
用mina也一段时间的,都不知道啥原理,经过一段时间的了解,学习的一个大概。其中有写的不好或者错了,请不要见怪,也给予纠结,谢谢。
学习mina的源码可以了解java很多api类,平常很少用到,例如:多线程包下类、原子变量等
还可以提高我们编程能力,等你深入学习后会更深有体会。
(其中一些个人建议,学习源码先学习下 Nio Reactor模式、过滤器链 、观察者模式,特别理解清楚Reactor模式更容易看懂源码)
Reactor模式参考:
http://www.cnblogs.com/alipayhutu/archive/2012/05/04/2483018.html
http://woming66.iteye.com/blog/1189748
http://wiki.jerrypeng.me/io-multiplexing-reactor.html
mina过滤器链:
http://www.iteye.com/topic/1124504