我们接着上一篇继续分析;
在addNow方法执行结束之后,我们已经为当前NioProcessor里面所有的NioSocketSession对应的SocketChannel注册了OP_READ事件,接下来继续查看Processor的run方法,源码在上一篇中有,执行到第49行,判断如果selected大于0执行第52行的process方法,selected的值其实就是Selector的select方法返回值,表示客户端存在和服务端交互的请求,那么我们看看process做了些什么事:
AbstractPollingIoProcessor$process()
private void process() throws Exception {
for (Iterator<S> i = selectedSessions(); i.hasNext();) {
S session = i.next();
process(session);
i.remove();
}
}
可以发现他就是遍历那些已经发生注册事件的NioSocketSession集合,并且调用process(S session)方法:
AbstractPollingIoProcessor$process()
private void process(S session) {
// Process Reads
if (isReadable(session) && !session.isReadSuspended()) {
read(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);
}
}
}
首先通过isReadable方法判断当前NioSocketSession对应的SocketChannel中是否注册过OP_READ事件,如果注册过的话,执行read(session)方法;
AbstractPollingIoProcessor$read()
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) {
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);
}
}
这部分代码比较长,我们了解主干就可以了;
首先第4行创建了一个IoBuffer对象,其实这就是我们java NIO中的Buffer角色,接着看到调用了read(session, buf)方法,这个方法返回值大于0表示读取数据成功,具体这个方法里面执行了些什么我们可以到NioProcessor里面的read方法看看:
protected int read(NioSession session, IoBuffer buf) throws Exception {
ByteChannel channel = session.getChannel();
return channel.read(buf.buf());
}
其实很简单了,就是将通道中的数据写到我们的缓存中罢了,这就是NIO本身的用法;
如果我们读取到了数据,就会执行第33行的if语句,在if语句块中会执行IoFilterChain的fireMessageReceived方法,其实呢,IoFilterChain就是我们的责任链,前面分析源码的过程中我们知道在创建NioSocketSession的时候会创建一个DefaultIoFilterChain出来,并且会在它里面创建一个EntryImpl链,默认情况下会创建一个HeadFilter链头和TailFilter链尾,那么这里的IoFilterChain其实就是对DefaultIoFilterChain进行转换过来的,默认情况下也就值存在链头和链尾了,我们在使用MINA的时候可以通过NioSocketAcceptor的getFilterChain获得其对应的IoFilterChain,其实getFilterChain的真正实现是在AbstarctIoService里面的,有了这个IoFilterChain之后,我们可以调用他的addLast方法为其添加我们自定义或者MINA自带的Filter对象,addLast的真正实现是在DefaultIoFilterChain里面的,我们可以看看:
public synchronized void addLast(String name, IoFilter filter) {
checkAddable(name);
register(tail.prevEntry, name, filter);
}
间接调用了register方法,来看看register
private void register(EntryImpl prevEntry, String name, IoFilter filter) {
EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);
try {
filter.onPreAdd(this, name, newEntry.getNextFilter());
} catch (Exception e) {
throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':' + filter + " in " + getSession(), e);
}
prevEntry.nextEntry.prevEntry = newEntry;
prevEntry.nextEntry = newEntry;
name2entry.put(name, newEntry);
try {
filter.onPostAdd(this, name, newEntry.getNextFilter());
} catch (Exception e) {
deregister0(newEntry);
throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':' + filter + " in " + getSession(), e);
}
}
如果你链表操作很熟的话,会发现其实这里进行的就是链表插入操作了,在第10行和11行可以体现出来,那么我们这里有个疑问了,链表操作的时候,我们只需要一个链头就可以了,没必要给链尾啊,这里的链尾是干嘛的呀,我来告诉你答案吧,链尾其实就是用来链接我们的IoHandler对象的,IoHandler是我们整个责任链的结束部分,我们真正的业务逻辑的处理都是在它里面完成的,所以你会发现在你使用MINA框架的时候,如果不给NioSocketAcceptor设置IoHandler的话是会报异常的,因为他是要进行业务逻辑处理的,没有他你整个程序是没法处理的,既然他是链接在链尾后面的,那么我们就该看看TailFilter的实现了:
他是DefaultIoFilterChain的静态内部类,代码比较长,我就截取两个方法,其他的方法类似啦:
private static class TailFilter extends IoFilterAdapter {
@Override
public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
try {
session.getHandler().sessionCreated(session);
} finally {
// Notify the related future.
ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_CREATED_FUTURE);
if (future != null) {
future.setSession(session);
}
}
}
@Override
public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
session.getHandler().sessionOpened(session);
}
}
可以看到在TailFiler里面执行的方法实际上都是执行的IoHandler中对应的方法啦,也就是这样我们把Filter责任链和IoHandler联系到了一起;
好了,扯得有点远了,继续回到我们的AbstractPollingIoProcessor里面的read方法,第33行在我们获取到数据之后首先会获得我们的DefaultIoFilterChain责任链,并且调用fireMessageReceived方法,我们来看看fireMessageReceived方法:
这个方法位于DefaultIoFilterChain中
public void fireMessageReceived(Object message) {
if (message instanceof IoBuffer) {
session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis());
}
callNextMessageReceived(head, session, message);
}
可以看到他调用的是callNextMessageReceived方法
private void callNextMessageReceived(Entry entry, IoSession session, Object message) {
try {
IoFilter filter = entry.getFilter();
NextFilter nextFilter = entry.getNextFilter();
filter.messageReceived(nextFilter, session, message);
} catch (Exception e) {
fireExceptionCaught(e);
} catch (Error e) {
fireExceptionCaught(e);
throw e;
}
}
在
callNextMessageReceived方法中首先会获得当前Filter对象,接着获得当前Filter的nextFilter对象,接着调用filter的messageReceived方法,这个方法其实上执行的是DefaultIoFilterChain的
messageReceived方法:
public void messageReceived(IoSession session, Object message) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextMessageReceived(nextEntry, session, message);
}
可以看到他还是执行的
callNextMessageReceived方法,这样层层递归的执行,直到Filter的链尾,那么接下来就是执行IoHandler里面对应的
messageReceived方法进行具体的业务逻辑操作喽!这样的话,整个read过程中涉及到的关键部分就结束啦!
接下来分析下write过程,如果我们想要给服务端发送消息内容的话,首先我们需要获取到IoSession对象,这里我们以NioSocketSession为例,发送消息调用的将是他的write方法,查看NioSocketSession发现他里面没有write方法,到他的父类NioSession查看也不存在,最后在AbstractIoSession找到啦;
AbstractIoSession$write()
public WriteFuture write(Object message) {
return write(message, null);
}
也就是说他执行的是两个参数的write方法,
public WriteFuture write(Object message, SocketAddress remoteAddress) {
if (message == null) {
throw new IllegalArgumentException("Trying to write a null message : not allowed");
}
// We can't send a message to a connected session if we don't have
// the remote address
if (!getTransportMetadata().isConnectionless() && (remoteAddress != null)) {
throw new UnsupportedOperationException();
}
// If the session has been closed or is closing, we can't either
// send a message to the remote side. We generate a future
// containing an exception.
if (isClosing() || !isConnected()) {
WriteFuture future = new DefaultWriteFuture(this);
WriteRequest request = new DefaultWriteRequest(message, future, remoteAddress);
WriteException writeException = new WriteToClosedSessionException(request);
future.setException(writeException);
return future;
}
FileChannel openedFileChannel = null;
// TODO: remove this code as soon as we use InputStream
// instead of Object for the message.
try {
if ((message instanceof IoBuffer) && !((IoBuffer) message).hasRemaining()) {
// Nothing to write : probably an error in the user code
throw new IllegalArgumentException("message is empty. Forgot to call flip()?");
} else if (message instanceof FileChannel) {
FileChannel fileChannel = (FileChannel) message;
message = new DefaultFileRegion(fileChannel, 0, fileChannel.size());
} else if (message instanceof File) {
File file = (File) message;
openedFileChannel = new FileInputStream(file).getChannel();
message = new FilenameFileRegion(file, openedFileChannel, 0, openedFileChannel.size());
}
} catch (IOException e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
return DefaultWriteFuture.newNotWrittenFuture(this, e);
}
// Now, we can write the message. First, create a future
WriteFuture writeFuture = new DefaultWriteFuture(this);
WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress);
// Then, get the chain and inject the WriteRequest into it
IoFilterChain filterChain = getFilterChain();
filterChain.fireFilterWrite(writeRequest);
// TODO : This is not our business ! The caller has created a
// FileChannel,
// he has to close it !
if (openedFileChannel != null) {
// If we opened a FileChannel, it needs to be closed when the write
// has completed
final FileChannel finalChannel = openedFileChannel;
writeFuture.addListener(new IoFutureListener<WriteFuture>() {
public void operationComplete(WriteFuture future) {
try {
finalChannel.close();
} catch (IOException e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
}
}
});
}
// Return the WriteFuture.
return writeFuture;
}
这部分源码比较长,我们挑重点看,在第45行创建了一个
WriteFuture对象,接着把write的消息内容以及WriteFuture对象对象作为参数封装出来一个WriteRequest对象,第49行获得了我们的责任链,和read过程一样,我们也可以通过DefaultIoFilterChain的addLast方法添加自己创建的Filter对象,接着第50行调用DefaultIoFilterChain的fireFilterWrite方法
public void fireFilterWrite(WriteRequest writeRequest) {
callPreviousFilterWrite(tail, session, writeRequest);
}
可以看到这个方法执行的是callPreviousFilterWrite方法
private void callPreviousFilterWrite(Entry entry, IoSession session, WriteRequest writeRequest) {
try {
IoFilter filter = entry.getFilter();
NextFilter nextFilter = entry.getNextFilter();
filter.filterWrite(nextFilter, session, writeRequest);
} catch (Exception e) {
writeRequest.getFuture().setException(e);
fireExceptionCaught(e);
} catch (Error e) {
writeRequest.getFuture().setException(e);
fireExceptionCaught(e);
throw e;
}
}
和之前的read方法中责任链的执行过程一样,也是首先获取filter对象,同时获取该filter对象的下一个nextFilter对象,调用他的filterWrite方法
@Override
public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
nextFilter.filterWrite(session, writeRequest);
}
它里面调用的是filterWrite方法,这个方法里面会继续调用filterWrite方法,这样层层递归,直到到达责任链的链头,也就是HeadFilter为止,调用HeadFilter的filterWrite方法,HeadFilter是DefaultIoFilterChain的静态内部类:
public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
AbstractIoSession s = (AbstractIoSession) session;
// Maintain counters.
if (writeRequest.getMessage() instanceof IoBuffer) {
IoBuffer buffer = (IoBuffer) writeRequest.getMessage();
// I/O processor implementation will call buffer.reset()
// it after the write operation is finished, because
// the buffer will be specified with messageSent event.
buffer.mark();
int remaining = buffer.remaining();
if (remaining > 0) {
s.increaseScheduledWriteBytes(remaining);
}
} else {
s.increaseScheduledWriteMessages();
}
WriteRequestQueue writeRequestQueue = s.getWriteRequestQueue();
if (!s.isWriteSuspended()) {
if (writeRequestQueue.isEmpty(session)) {
// We can write directly the message
s.getProcessor().write(s, writeRequest);
} else {
s.getWriteRequestQueue().offer(s, writeRequest);
s.getProcessor().flush(s);
}
} else {
s.getWriteRequestQueue().offer(s, writeRequest);
}
}
在
HeadFilter的filterWrite方法里面,你会看到有这么一句代码s.getProcessor(),他其实上就是获得处理我们当前NioSocketSession的NioProcessor对象而已,那么接下来的write操作是包含两个参数的,我们的NioProcessor里面并没有实现这个方法,需要到他的父类AbstractPollingIoProcessor查看,代码如下:
public void write(S session, WriteRequest writeRequest) {
WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();
writeRequestQueue.offer(session, writeRequest);
if (!session.isWriteSuspended()) {
this.flush(session);
}
}
做的事还是比较少的,就是将当前的写请求加入到我们当前NioSocketSession的写请求队列中,同时通过AbstractPollingIoProcessor的flush方法将NioSocketSession放入到flushingSessions队列中,这个队列主要存储的是那些将要被flush的IoSession集合;我们来看看flush方法
AbstractPollingIoProcessor$flush
public final void flush(S session) {
// add the session to the queue if it's not already
// in the queue, then wake up the select()
if (session.setScheduledForFlush(true)) {
flushingSessions.add(session);
wakeup();
}
}
第5行执行了将当前NioSocketSession加入到flushingSession的操作,随后调用了wakeup方法,wakeup方法会唤醒我们阻塞的select方法,这样的话,我们的服务端就可以收到客户端发送的消息了,接着读取过程就和上面的源码讲解一样了;
至此,MINA中主要的服务端源码分析结束了,注意我们只分析了NioSocketAcceptor部分的源码,没有涉及NioSocketConnector部分,其实NioSocketConnector部分的源码和NioSocketAcceptor部分基本上是类似的分析过程,在这里我就不细细分析了,下一篇我会对MINA框架做一个小结,包括它里面涉及到的一些线程模型结构;