从Server和Client2个方向总结一下MINA的类设计,主要是基于NIO的。
一、公共类设计。
Server和Client端都会继承或使用的类。
1、IoService:采用观察者模式的基础接口,Server和Client都会继承这个类的抽象实现类,将自己定义为被观察者。同时可以获取Session和FIlterChain。这种观察者的设计模式同Tomcat的LifeCycle设计。
2、AbstractIoService:IoService的抽象实现类,主要的属性是线程池executor,用于处理IO事件的IoHandler。
采用匿名内部类的方式构造了一个观察者,用于监听该服务的启动。
线程池的作用的对于每一个绑定的端口,采用单独的一个线程来执行通信。
3、IoServiceListenerSupport:用于保存所有观察者的辅助类。观察者的操作,和事件的触发都在这个类里。
二、Server
1、IoAcceptor:Server端的最底层接口。主要的方法为LoacaAddress的get和set,bind和unbind方法。当我们进行NIO的通信时,绑定监听的端口是必须的,这就是这个接口的作用。
2、AbstractIoAcceptor:实现IoAccpetor,继承AbstractIoService。
bind方法,绑定设置的端口,成功后触发观察者的服务启动事件。public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {
...
boolean activate = false;
synchronized (bindLock) {
synchronized (boundAddresses) {
if (boundAddresses.isEmpty()) {
activate = true;
}
}
if (getHandler() == null) {
throw new IllegalStateException("handler is not set.");
}
try {
//调用子类的方法实现绑定。
Set<socketaddress> addresses = bindInternal(localAddressesCopy);
synchronized (boundAddresses) {
boundAddresses.addAll(addresses);
}
} catch (IOException e) {
throw e;
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeIoException("Failed to bind to: " + getLocalAddresses(), e);
}
}
if (activate) {
//触发服务启动事件
getListeners().fireServiceActivated();
}
}
</socketaddress>
线程池执行线程,子类会调用。
protected final void executeWorker(Runnable worker) {
executeWorker(worker, null);
}
protected final void executeWorker(Runnable worker, String suffix) {
String actualThreadName = threadName;
if (suffix != null) {
actualThreadName = actualThreadName + '-' + suffix;
}
executor.execute(new NamePreservingRunnable(worker, actualThreadName));
}
3、AbstractPollingIoAcceptor:继承AbstractIoAcceptor。
定义了ServerSocketChannel的open,accept抽象方法以及Selector的open和select的抽象方法。
bind的最终实现方法。protected final Set<socketaddress> bindInternal(List<? extends SocketAddress> localAddresses) throws Exception {
...
//主要方法
startupAcceptor();
...
}
private void startupAcceptor() throws InterruptedException {
...
Acceptor acceptor = acceptorRef.get();
//Acceptor为内部类,
if (acceptor == null) {
lock.acquire();
acceptor = new Acceptor();
//线程池执行该内部类
if (acceptorRef.compareAndSet(null, acceptor)) {
executeWorker(acceptor);
} else {
lock.release();
}
}
}
private class Acceptor implements Runnable {
public void run() {
assert (acceptorRef.get() == this);
int nHandles = 0;
// Release the lock
lock.release();
while (selectable) {
try {
//selector.select();
int selected = select();
//在管道上注册ACCPET事件,绑定端口
nHandles += registerHandles();
//没有成功绑定端口
if (nHandles == 0) {
acceptorRef.set(null);
if (registerQueue.isEmpty() && cancelQueue.isEmpty()) {
assert (acceptorRef.get() != this);
break;
}
if (!acceptorRef.compareAndSet(null, this)) {
assert (acceptorRef.get() != this);
break;
}
assert (acceptorRef.get() == this);
}
//成功绑定了端口,生成了SSc
if (selected > 0) {
//处理每个SSC,生成对应的Session
processHandles(selectedHandles());
}
// check to see if any cancellation request has been made.
nHandles -= unregisterHandles();
} catch (ClosedSelectorException cse) {
// If the selector has been closed, we can exit the loop
ExceptionMonitor.getInstance().exceptionCaught(cse);
break;
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
ExceptionMonitor.getInstance().exceptionCaught(e1);
}
}
}
// Cleanup all the processors, and shutdown the acceptor.
if (selectable && isDisposing()) {
selectable = false;
try {
if (createdProcessor) {
processor.dispose();
}
} finally {
try {
synchronized (disposalLock) {
if (isDisposing()) {
destroy();
}
}
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
} finally {
disposalFuture.setDone();
}
}
}
}
private int registerHandles() {
for (;;) {
...
try {
// Process all the addresses
for (SocketAddress a : localAddresses) {
//调用父类方法,进行ServerSocketChannel生成等NIO初始化操作。循环遍历每个绑定的端口。
H handle = open(a);
//端口号的类为key,ServerSocketChannel为value存入map中。
newHandles.put(localAddress(handle), handle);
}
// Everything went ok, we can now update the map storing
// all the bound sockets.
boundHandles.putAll(newHandles);
// and notify.
future.setDone();
return newHandles.size();
} catch (Exception e) {
// We store the exception in the future
future.setException(e);
} finally {
// Roll back if failed to bind all addresses.
if (future.getException() != null) {
for (H handle : newHandles.values()) {
try {
close(handle);
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
}
}
// TODO : add some comment : what is the wakeup() waking up ?
wakeup();
}
}
}
}
protected ServerSocketChannel open(SocketAddress localAddress) throws Exception {
//所有NIO的Server端初始化都在这里
ServerSocketChannel channel = null;
if (selectorProvider != null) {
channel = selectorProvider.openServerSocketChannel();
} else {
channel = ServerSocketChannel.open();
}
boolean success = false;
try {
//非阻塞
channel.configureBlocking(false);
//获取socket
ServerSocket socket = channel.socket();
// Set the reuseAddress flag accordingly with the setting
socket.setReuseAddress(isReuseAddress());
try {
//绑定
socket.bind(localAddress, getBacklog());
} catch (IOException ioe) {
// Add some info regarding the address we try to bind to the
// message
String newMessage = "Error while binding on " + localAddress + "\n" + "original message : "
+ ioe.getMessage();
Exception e = new IOException(newMessage);
e.initCause(ioe.getCause());
// And close the channel
channel.close();
throw e;
}
//在SSC上注册ACCEPT事件
channel.register(selector, SelectionKey.OP_ACCEPT);
success = true;
} finally {
if (!success) {
close(channel);
}
}
return channel;
}
private void processHandles(Iterator<h> handles) throws Exception {
//循环处理每个SSC
while (handles.hasNext()) {
H handle = handles.next();
handles.remove();
//监听ACCEPT事件,有就新建Session
S session = accept(processor, handle);
if (session == null) {
continue;
}
//初始化
initSession(session, null, null);
//getProcessor()获取的是SimpleIoProcessorPool,add方法是拿到池子里的IOProcessor,然后添加session。
session.getProcessor().add(session);
}
}
</h>
protected NioSession accept(IoProcessor<niosession> processor, ServerSocketChannel handle) throws Exception {
SelectionKey key = null;
if (handle != null) {
//获取所有的事件
key = handle.keyFor(selector);
}
//不是ACCEPT事件就返回
if ((key == null) || (!key.isValid()) || (!key.isAcceptable())) {
return null;
}
//接受客户端的SocketChannel,
SocketChannel ch = handle.accept();
if (ch == null) {
return null;
}
//生成Session
return new NioSocketSession(this, processor, ch);
}
</niosession>
public final void add(S session) {
if (disposed || disposing) {
throw new IllegalStateException("Already disposed.");
}
//往当前IOProcessor的队列里添加session
newSessions.add(session);
//和之前的startupAcceptor类似,通过IOProcessor的线程池执行processor。
startupProcessor();
}
private class Processor implements Runnable {
public void run() {
assert (processorRef.get() == this);
int nSessions = 0;
lastIdleCheckTime = System.currentTimeMillis();
for (;;) {
try {
...
//对Session处理,主要是在管道上注册READ事件,然后将Session附着(attach)在管道上。
nSessions += handleNewSessions();
updateTrafficMask();
// Now, if we have had some incoming or outgoing events,
// deal with them
if (selected > 0) {
//处理read和write事件
process();
}
// Write the pending requests
long currentTime = System.currentTimeMillis();
flush(currentTime);
// And manage removed sessions
nSessions -= removeSessions();
// Last, not least, send Idle events to the idle sessions
notifyIdleSessions(currentTime);
// Get a chance to exit the infinite loop if there are no
// more sessions on this Processor
if (nSessions == 0) {
processorRef.set(null);
if (newSessions.isEmpty() && isSelectorEmpty()) {
// newSessions.add() precedes startupProcessor
assert (processorRef.get() != this);
break;
}
assert (processorRef.get() != this);
if (!processorRef.compareAndSet(null, this)) {
// startupProcessor won race, so must exit processor
assert (processorRef.get() != this);
break;
}
assert (processorRef.get() == this);
}
// Disconnect all sessions immediately if disposal has been
// requested so that we exit this loop eventually.
if (isDisposing()) {
for (Iterator<> i = allSessions(); i.hasNext();) {
scheduleRemove(i.next());
}
wakeup();
}
} catch (ClosedSelectorException cse) {
// If the selector has been closed, we can exit the loop
// But first, dump a stack trace
ExceptionMonitor.getInstance().exceptionCaught(cse);
break;
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
ExceptionMonitor.getInstance().exceptionCaught(e1);
}
}
}
try {
synchronized (disposalLock) {
if (disposing) {
doDispose();
}
}
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
} finally {
disposalFuture.setValue(true);
}
}
}
private boolean addNow(S session) {
boolean registered = false;
try {
//注册READ事件,管道附着Session
init(session);
registered = true;
//建立Session中的FilterChain
IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder();
chainBuilder.buildFilterChain(session.getFilterChain());
//观察者模式触发SessionCreated
IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners();
listeners.fireSessionCreated(session);
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
try {
destroy(session);
} catch (Exception e1) {
ExceptionMonitor.getInstance().exceptionCaught(e1);
} finally {
registered = false;
}
}
return registered;
}
protected void init(NioSession session) throws Exception {
SelectableChannel ch = (SelectableChannel) session.getChannel();
ch.configureBlocking(false);
//注册READ事件,管道附着Session
session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
}
private void process(S session) {
// 处理读取事件
if (isReadable(session) && !session.isReadSuspended()) {
read(session);
}
// 处理写事件
if (isWritable(session) && !session.isWriteSuspended()) {
// add the session to the queue, if it's not already there
if (session.setScheduledForFlush(true)) {
flushingSessions.add(session);
}
}
}
private void read(S session) {
IoSessionConfig config = session.getConfig();
int bufferSize = config.getReadBufferSize();
IoBuffer buf = IoBuffer.allocate(bufferSize);
final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation();
try {
int readBytes = 0;
int ret;
//获取传输内容大小
try {
if (hasFragmentation) {
while ((ret = read(session, buf)) > 0) {
readBytes += ret;
if (!buf.hasRemaining()) {
break;
}
}
} else {
ret = read(session, buf);
if (ret > 0) {
readBytes = ret;
}
}
} finally {
buf.flip();
}
if (readBytes > 0) {
//有传输数据,这样通过责任链触发Server端的MessageReceived方法。
//默认的责任链有TailFilter,其中的onMessageReceived会调用handler的onMessageReceived,
//这样就会调用到我们初始化设置的handler了。
IoFilterChain filterChain = session.getFilterChain();
filterChain.fireMessageReceived(buf);
buf = null;
if (hasFragmentation) {
if (readBytes << 1 < config.getReadBufferSize()) {
session.decreaseReadBufferSize();
} else if (readBytes == config.getReadBufferSize()) {
session.increaseReadBufferSize();
}
}
}
if (ret < 0) {
// scheduleRemove(session);
IoFilterChain filterChain = session.getFilterChain();
filterChain.fireInputClosed();
}
} catch (Exception e) {
if (e instanceof IOException) {
if (!(e instanceof PortUnreachableException)
|| !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
|| ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable()) {
scheduleRemove(session);
}
}
IoFilterChain filterChain = session.getFilterChain();
filterChain.fireExceptionCaught(e);
}
}
总结:1、服务端初始化时,会生成SimpleIoProcessorPool,用来处理Session。2、需要继承IoHandlerAdapter来实现自己的handler,用于接受消息。3、绑定端口的时候,会初始化NIO的ServerSocketChannel(SSC),注册ACCEPTOR事件。之后会通过IOService的线程池处理每一个端口的ACCEPTOR事件,成功后生成NioSocketSession,附着在SSC上。每个Session都会有IOProcessor,通过线程池,将SSC注册READ事件,同时监听是否有read事件,有read事件就触发责任链的onMessageReceived方法,最后会调用到自己实现的handler的onMessageReceived方法。