这一章讲的就是IoSession,session这个词做web应用的人应该都是耳熟能详,在mina中IoSession也是起着相同的作用。mina为每个客户端提供了会话session,session是服务器端和客户端的连接持有者,直到连接中断session才会被销毁。
IoSession不仅是connection的相关信息,同时,服务器端还能通过他存储其他可能需要的数据信息。好,让我们一步一步剖析IoSession那不平凡的一生吧。
Acceptor.run(){
...
//selectedHandles()获取一个selector中注册的服务监听的serversocketchannel的迭代器
processHandles(selectedHandles());
...
}
创建session、并为其分配指定IoProcessor的秘密都在AbstractPollingIoAcceptor.processHandles()这个方法中。我们接着看:
private void processHandles(Iterator handles) throws Exception {
while (handles.hasNext()) {
H handle = handles.next();
handles.remove();
// 创建session并将本地的processor处理池当参数传递给session
// 注意这里还未分配具体的processor
S session = accept(processor, handle);
if (session == null) {
continue;
}
// 初始化Session
initSession(session, null, null);
// 将session分配给具体的processor
session.getProcessor().add(session);
}
}
第一步accept(processor,handle)方法,调用子类实现的NioSession accept(...)方法,判断了SelectionKey的有效性后,获得连接的通道SocketChannel ch = handle.accept();最后以此为传参创建IoSession对象return new NioSocketSession(this, processor, ch);我们看下构造函数做了什么(为了方便起见,相关的父类构造函数都写在一块了):
public NioSocketSession(IoService service, IoProcessor processor, SocketChannel channel) {
//AbstractIoSession(IoService service)
this.service = service;
this.handler = service.getHandler();
//保存当前的处理时间信息
long currentTime = System.currentTimeMillis();
creationTime = currentTime;
lastThroughputCalculationTime = currentTime;
lastReadTime = currentTime;
lastWriteTime = currentTime;
lastIdleTimeForBoth = currentTime;
lastIdleTimeForRead = currentTime;
lastIdleTimeForWrite = currentTime;
//在关闭时的动作,下面以此展开对IoFuture的探讨。
closeFuture.addListener(SCHEDULED_COUNTER_RESETTER);
//为session创建唯一的ID
sessionId = idGenerator.incrementAndGet();
//END AbstractIoSession(IoService service)
//NioSession(IoProcessor processor, IoService service, Channel channel)
//即当前session的SocketChannel
this.channel = channel;
//这是ioservice中的processor池哦
this.processor = processor;
//这步过滤器链厉害了,后面细说
filterChain = new DefaultIoFilterChain(this);
//END NioSession(IoProcessor processor, IoService service, Channel channel)
//设置各种初始参数
config = new SessionConfigImpl();
this.config.setAll(service.getSessionConfig());
}
右边这张图是IoSession的类图结构,比较清晰。
addListener(IoFutureListener>)
await()
await(long)
await(long, TimeUnit)
awaitUninterruptibly()
awaitUninterruptibly(long)
awaitUninterruptibly(long, TimeUnit)
getSession()
isDone()
removeListener(IoFutureListener>)
从清单我们了解到:1.IoFuture支持添加操作完成的监听器,2.IoFuture支持可中断、可设置超时时间的阻塞式操作。3.isDone()则返回操作的完成状态。
public interface IoFutureListener extends EventListener {
void operationComplete(F future);
}
public void setValue(Object newValue) {
synchronized (lock) {
// 已经完成则直接返回
if (ready) {
return;
}
//设置结果
result = newValue;
//设置完成状态
ready = true;
//唤醒所有等待线程
if (waiters > 0) {
lock.notifyAll();
}
}
//通知监听器执行完成操作
notifyListeners();
}
DefaultIoFuture中个还有一个检查死锁的方法,大家有兴趣可以看下是怎么判断死锁的:
private void checkDeadLock() {
// Only read / write / connect / write future can cause dead lock.
if (!(this instanceof CloseFuture || this instanceof WriteFuture || this instanceof ReadFuture || this instanceof ConnectFuture)) {
return;
}
// Get the current thread stackTrace.
// Using Thread.currentThread().getStackTrace() is the best solution,
// even if slightly less efficient than doing a new Exception().getStackTrace(),
// as internally, it does exactly the same thing. The advantage of using
// this solution is that we may benefit some improvement with some
// future versions of Java.
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
// Simple and quick check.
for (StackTraceElement s : stackTrace) {
if (AbstractPollingIoProcessor.class.getName().equals(s.getClassName())) {
IllegalStateException e = new IllegalStateException("t");
e.getStackTrace();
throw new IllegalStateException("DEAD LOCK: " + IoFuture.class.getSimpleName()
+ ".await() was invoked from an I/O processor thread. " + "Please use "
+ IoFutureListener.class.getSimpleName() + " or configure a proper thread model alternatively.");
}
}
// And then more precisely.
for (StackTraceElement s : stackTrace) {
try {
Class> cls = DefaultIoFuture.class.getClassLoader().loadClass(s.getClassName());
if (IoProcessor.class.isAssignableFrom(cls)) {
throw new IllegalStateException("DEAD LOCK: " + IoFuture.class.getSimpleName()
+ ".await() was invoked from an I/O processor thread. " + "Please use "
+ IoFutureListener.class.getSimpleName()
+ " or configure a proper thread model alternatively.");
}
} catch (Exception cnfe) {
// Ignore
}
}
}
filterChain = new DefaultIoFilterChain(this);
try {
((AbstractIoSession) session).setAttributeMap(session.getService().getSessionDataStructureFactory()
.getAttributeMap(session));
} catch (IoSessionInitializationException e) {
throw e;
} catch (Exception e) {
throw new IoSessionInitializationException("Failed to initialize an attributeMap.", e);
}
try {
((AbstractIoSession) session).setWriteRequestQueue(session.getService().getSessionDataStructureFactory()
.getWriteRequestQueue(session));
} catch (IoSessionInitializationException e) {
throw e;
} catch (Exception e) {
throw new IoSessionInitializationException("Failed to initialize a writeRequestQueue.", e);
}
public final void add(S session) {
//请注意这里是两步,第一步getProcessor(session)在下面段代码,创建(若没有)并返回Processor
//第二步在该Processor中add(session),这里就是调用AbstractPollingIoProcessor.add(),后面有更多描述
getProcessor(session).add(session);
}
private IoProcessor getProcessor(S session) {
IoProcessor processor = (IoProcessor) 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];
if (processor == null) {
throw new IllegalStateException("A disposed processor cannot be accessed.");
}
session.setAttributeIfAbsent(PROCESSOR, processor);
}
return processor;
}
for (int i = 1; i < pool.length; i++) {
...
pool[i] = processorConstructor.newInstance(this.executor);
...
}
这段代码将生成的线程池当做构造传参传递给所有的NioProcess,即数组池中所有NioProcess都是共享一个Executro线程池的(newCashedThreadPool)。AbstractPollingIoProcessor.add()方法做了这些工作:
public final void add(S session) {
if (disposed || disposing) {
throw new IllegalStateException("Already disposed.");
}
// 将session添加到ConcurrentLinkedQueue的队列中,并启动Processor 的worker线程
newSessions.add(session);
//启动Processor线程
startupProcessor();
}
private class Processor implements Runnable {
public void run() {
...
for (;;) {
try {
// 监控空闲时间
long t0 = System.currentTimeMillis();
int selected = select(1000);
long t1 = System.currentTimeMillis();
long delta = (t1 - t0);
...
// 注册新的session连接,并初始化session信息,如过滤器链,
// 通知service的监听器
nSessions += handleNewSessions();
...
// 处理新的请求
if (selected > 0) {
process();
}
...
// 移除
nSessions -= removeSessions();
// 通知空闲监听器
notifyIdleSessions(currentTime);
...
//关闭
if (isDisposing()) {
for (Iterator i = allSessions(); i.hasNext();) {
scheduleRemove(i.next());
}
wakeup();
}
} catch ...
}
...
}
}
其中,handlesNewSessions()做了如下工作:
//在selector上注册感兴趣的相应集合读操作
SelectableChannel ch = (SelectableChannel) session.getChannel();
ch.configureBlocking(false);
session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
//将service的过滤器链设置在session上
IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder();
chainBuilder.buildFilterChain(session.getFilterChain());
//回调监听器
IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners();
listeners.fireSessionCreated(session);
至此SimpleIoProcessorPool、IoProcess和IoServices的关系就清晰了。
public NioProcessor(Executor executor) {
super(executor);
try {
selector = Selector.open();
} catch (IOException e) {
throw new RuntimeIoException("Failed to open a selector.", e);
}
}
NioSocketAcceptor.init() throws Exception {
selector = Selector.open();
}