本文分析中贴出的代码简化了原版的代码,方便查看。
使用Mina第一步是构造一个acceptor,第二部是设置acceptor相应的Handler事件处理器,第三部就是调用bind函数开始监听连接。下面一一分析。
本章分析Mina框架,主要分析NioSocketAcceptor。
NioSocketAcceptor属于Mina框架中的Acceptor,用来处理客户端的连接。首先看NioSocketAcceptor的继承关系,
public final class NioSocketAcceptor extends AbstractPollingIoAcceptor<NioSession, ServerSocketChannel> implements SocketAcceptor public abstract class AbstractPollingIoAcceptor<S extends AbstractIoSession, H> extends AbstractIoAcceptor public abstract class AbstractIoAcceptor extends AbstractIoService implements IoAcceptor public abstract class AbstractIoService implements IoService
再看NioSocketAcceptor的构造函数
public NioSocketAcceptor(int processorCount) {
super(new DefaultSocketSessionConfig(), NioProcessor.class, processorCount);
((DefaultSocketSessionConfig) getSessionConfig()).init(this);
}
NioSocketAcceptor的父类AbstractPollingIoAcceptor的构造函数如下
protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig, Class<? extends IoProcessor<S>> processorClass, int processorCount) {
this(sessionConfig, null, new SimpleIoProcessorPool<S>(processorClass, processorCount), true, null);
}
SimpleIoProcessorPool会根据Java虚拟机用到的cpu数量构造一个池,代码如下所示
public SimpleIoProcessorPool(Class<? extends IoProcessor<S>> processorType, Executor executor, int size, SelectorProvider selectorProvider) {
if (createdExecutor) {
this.executor = Executors.newCachedThreadPool();
((ThreadPoolExecutor) this.executor).setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
} else {
this.executor = executor;
}
pool = new IoProcessor[size];
boolean success = false;
Constructor<? extends IoProcessor<S>> processorConstructor = null;
boolean usesExecutorArg = true;
try {
try {
try {
processorConstructor = processorType.getConstructor(ExecutorService.class);
pool[0] = processorConstructor.newInstance(this.executor);
} catch () {
}
} catch () {
}
for (int i = 1; i < pool.length; i++) {
try {
if (usesExecutorArg) {
if(selectorProvider==null) {
pool[i] = processorConstructor.newInstance(this.executor);
} else {
pool[i] = processorConstructor.newInstance(this.executor, selectorProvider);
}
} else {
pool[i] = processorConstructor.newInstance();
}
} catch (Exception e) {
}
}
success = true;
} finally {
if (!success) {
dispose();
}
}
}
newCachedThreadPool构造了一个线程池ThreadPoolExecutor。setRejectedExecutionHandler设置当拒绝执行任务时的回调函数,这和主线无关,因此不往下分析了。传入的参数processorType是NioProcessor,下面会利用Java反射机制调用它的构造函数,
public NioProcessor(Executor executor) {
super(executor);
try {
selector = Selector.open();
} catch (IOException e) {
}
}
这里通过open创建了一个NIO的selector,关于NIO的源码分析不是本章的重点,因此就不往下分析了。回到SimpleIoProcessorPool构造函数中,接下来是一个for循环,继续构造相应的NioProcessor。
再回到AbstractPollingIoAcceptor构造函数中,接下来会调用AbstractPollingIoAcceptor的另一个构造函数,在该函数中,会调用其父类AbstractIoAcceptor的构造函数,再往上调用其父类AbstractIoService的构造函数,如下
protected AbstractIoService(IoSessionConfig sessionConfig, Executor executor) {
listeners = new IoServiceListenerSupport(this);
listeners.add(serviceActivationListener);
this.sessionConfig = sessionConfig;
ExceptionMonitor.getInstance();
if (executor == null) {
this.executor = Executors.newCachedThreadPool();
createdExecutor = true;
} else {
this.executor = executor;
createdExecutor = false;
}
threadName = getClass().getSimpleName() + '-' + id.incrementAndGet();
}
这里主要是构造了一个监听器列表类IoServiceListenerSupport,serviceActivationListener是一个IoServiceListener监听器,把它添加到IoServiceListenerSupport中。传入的参数executor为null,因此这里还需调用newCachedThreadPool构造一个ThreadPoolExecutor。
接下来调用NioSocketAcceptor设置处理函数,定义在其父类AbstractIoService中。
public final void setHandler(IoHandler handler) {
this.handler = handler;
}
bind函数最终会调用NioSocketAcceptor的父类AbstractIoAcceptor中的bind函数,如下
public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {
List<SocketAddress> localAddressesCopy = new ArrayList<SocketAddress>();
for (SocketAddress a : localAddresses) {
checkAddressType(a);
localAddressesCopy.add(a);
}
boolean activate = false;
synchronized (bindLock) {
synchronized (boundAddresses) {
if (boundAddresses.isEmpty()) {
activate = true;
}
}
try {
Set<SocketAddress> addresses = bindInternal(localAddressesCopy);
synchronized (boundAddresses) {
boundAddresses.addAll(addresses);
}
} catch (IOException e) {
throw e;
}
}
if (activate) {
getListeners().fireServiceActivated();
}
}
这里主要会调用两个函数,一是bindInternal,二是调用监听器的fireServiceActivated函数。监听器由用户自定义实现。下面主要看bindInternal函数,定义在AbstractPollingIoAcceptor中,
protected final Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws Exception {
AcceptorOperationFuture request = new AcceptorOperationFuture(localAddresses);
registerQueue.add(request);
startupAcceptor();
...
}
AcceptorOperationFuture和信号有关系,这里不管它,到用到的时候再分析。重点看startupAcceptor这个函数,
private void startupAcceptor() throws InterruptedException {
if (!selectable) {
registerQueue.clear();
cancelQueue.clear();
}
Acceptor acceptor = acceptorRef.get();
if (acceptor == null) {
lock.acquire();
acceptor = new Acceptor();
if (acceptorRef.compareAndSet(null, acceptor)) {
executeWorker(acceptor);
} else {
lock.release();
}
}
}
这里构造了一个Acceptor,添加到acceptorRef中,然后调用executeWorker启动线程执行该Acceptor。executeWorker就是启动一个线程,并执行Acceptor的run函数,
public void run() {
int nHandles = 0;
while (selectable) {
try {
int selected = select();
nHandles += registerHandles();
if (selected > 0) {
processHandles(selectedHandles());
}
nHandles -= unregisterHandles();
} catch (Exception e) {
}
}
}
select定义在NioSocketAcceptor中,
protected int select() throws Exception {
return selector.select();
}
该函数和NIO相关,其底层就是一个轮询,查看是否有事件发生。
registerHandles定义在AbstractPollingIoAcceptor中,用于设置Socket的连接,
private int registerHandles() {
for (;;) {
AcceptorOperationFuture future = registerQueue.poll();
Map<SocketAddress, H> newHandles = new ConcurrentHashMap<SocketAddress, H>();
List<SocketAddress> localAddresses = future.getLocalAddresses();
try {
for (SocketAddress a : localAddresses) {
H handle = open(a);
newHandles.put(localAddress(handle), handle);
}
boundHandles.putAll(newHandles);
future.setDone();
return newHandles.size();
} catch (Exception e) {
} finally {
}
}
}
这里通过AcceptorOperationFuture得到的localAddress便是前面注册的主机地址,重点看这个open函数,定义在NioSocketAcceptor中,
protected ServerSocketChannel open(SocketAddress localAddress) throws Exception {
ServerSocketChannel channel = null;
if (selectorProvider != null) {
channel = selectorProvider.openServerSocketChannel();
} else {
channel = ServerSocketChannel.open();
}
boolean success = false;
try {
channel.configureBlocking(false);
ServerSocket socket = channel.socket();
socket.setReuseAddress(isReuseAddress());
try {
socket.bind(localAddress, getBacklog());
} catch (IOException ioe) {
}
channel.register(selector, SelectionKey.OP_ACCEPT);
success = true;
} finally {
}
return channel;
}
这里就是构造openfire服务器监听连接的那个Socket,首先构造一个ServerSocketChannel,设置模式为非阻塞(因为NIO嘛),再调用bind函数绑定服务器地址,最后调用register注册OP_ACCEPT事件到selector中,这样后面调用select就可以监听该事件了。
回到registerHandles中,接下来就把对应的地址和刚刚构造的ServerSocketChannel注册到newHandles中。
再回到run函数中,先看一下unregisterHandles,定义在AbstractPollingIoAcceptor中,
private int unregisterHandles() {
int cancelledHandles = 0;
for (;;) {
AcceptorOperationFuture future = cancelQueue.poll();
if (future == null) {
break;
}
for (SocketAddress a : future.getLocalAddresses()) {
H handle = boundHandles.remove(a);
try {
close(handle);
} catch (Exception e) {
} finally {
cancelledHandles++;
}
}
future.setDone();
}
return cancelledHandles;
}
这里就是检查cancelQueue是否有需要关闭的服务器地址,如果有,就取出前面注册进的ServerSocketChannel,调用close关闭它。
再看run函数,首先selectedHandles用于从NIO的Selector中获取的事件,保存在ServerSocketChannelIterator中,然后调用processHandles开始处理。该函数的分析放在下一章中。