为了能够观察此事件,我修改了源码,抛出异常。
/**
* {@inheritDoc}
*/
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
System.out.println("1");
if(1==1)throw new Exception("message Received...");
然后在eclipse里运行,得到的线程栈如下:
java.lang.Exception: message Received...Session closed...
Nb message received : 0
at org.apache.mina.example.tcp.perf.TcpServer.messageReceived(TcpServer.java:68)
at org.apache.mina.core.filterchain.DefaultIoFilterChain$TailFilter.messageReceived(DefaultIoFilterChain.java:854)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:542)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$6(DefaultIoFilterChain.java:538)
at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceived(DefaultIoFilterChain.java:943)
at org.apache.mina.core.filterchain.IoFilterAdapter.messageReceived(IoFilterAdapter.java:109)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:542)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.fireMessageReceived(DefaultIoFilterChain.java:535)
at org.apache.mina.core.polling.AbstractPollingIoProcessor.read(AbstractPollingIoProcessor.java:714)
at org.apache.mina.core.polling.AbstractPollingIoProcessor.process(AbstractPollingIoProcessor.java:668)
at org.apache.mina.core.polling.AbstractPollingIoProcessor.process(AbstractPollingIoProcessor.java:657)
at org.apache.mina.core.polling.AbstractPollingIoProcessor.access$10(AbstractPollingIoProcessor.java:654)
at org.apache.mina.core.polling.AbstractPollingIoProcessor$Processor.run(AbstractPollingIoProcessor.java:1121)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:64)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
这个线程其实就是具体运行客户端IO的线程。
好,我们来顺着运行栈看看到底是如何调用的。
---------------------------------------------------不过先看看filterChain是如何创建的吧
Step completed: "thread=NioSocketAcceptor-1", org.apache.mina.transport.socket.nio.NioSession.<init>(), line=63 bci=15
63 filterChain = new DefaultIoFilterChain(this);
先看DefaultIoFilterChain的初始化做了什么操作。
public DefaultIoFilterChain(AbstractIoSession session) {
if (session == null) {
throw new IllegalArgumentException("session");
}
this.session = session;
head = new EntryImpl(null, null, "head", new HeadFilter());
tail = new EntryImpl(head, null, "tail", new TailFilter());
head.nextEntry = tail;
}
这部分代码一定要理解透!(我就不具体画图了,读者自行分析吧)。
------------------------
好了,初始化完毕后,再接着刚才的栈进来分析。
刚开始是 at org.apache.mina.core.polling.AbstractPollingIoProcessor.process(AbstractPollingIoProcessor.java:668)
再调用read函数 at org.apache.mina.core.polling.AbstractPollingIoProcessor.read(AbstractPollingIoProcessor.java:714)
一旦发现有消息OK的话,这里的消息就是读了至少1个字节。
就触发 at org.apache.mina.core.filterchain.DefaultIoFilterChain.fireMessageReceived(DefaultIoFilterChain.java:535)
可见,之前初始化的DefaultIoFilterChain对象在这里开始介入了。
这个fireMessageReceived的函数定义为
public void fireMessageReceived(Object message) {
if (message instanceof IoBuffer) {
session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis());
}
callNextMessageReceived(head, session, message);
}
也就是说实际上是调用了callNextMessageReceived函数。
这个从栈日志 at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:542)
也可以得到验证。
下面我们进入这个函数(注意函数的第一个参数:head)
private void callNextMessageReceived(Entry entry, IoSession session, Object message) {
try {
IoFilter filter = entry.getFilter();// 第1行
NextFilter nextFilter = entry.getNextFilter();//第2行
filter.messageReceived(nextFilter, session, message);//第3行
} catch (Exception e) {
fireExceptionCaught(e);
} catch (Error e) {
fireExceptionCaught(e);
throw e;
}
}
这里需要仔细一点。
先来分析第1行:IoFilter filter = entry.getFilter();// 第1行
public IoFilter getFilter() {
return filter;
}
那么对于head来说,这里返回的就是之前初始化的new HeadFilter()对象。
再看第2行NextFilter nextFilter = entry.getNextFilter();//第2行
public NextFilter getNextFilter() {
return nextFilter;
}
对于head来说,也就是返回初始化的一个new NextFilter()对象。
再看第3行 filter.messageReceived(nextFilter, session, message);//第3行
开始调用了。
再具体分析下去!
疑问:这个时候的tail干嘛去了?
----------------------------------------
at org.apache.mina.core.filterchain.IoFilterAdapter.messageReceived(IoFilterAdapter.java:109)
从这个函数来分析!
/**
* {@inheritDoc}
*/
public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
nextFilter.messageReceived(session, message);
}
也就是说,自己什么都不做,直接调用nextFilter的函数。
别忘了这个nextFilter函数实际上是new NextFilter对象,所以我们进入这个对象的方法。
这个实际上是定义了一个内部类对象,所以又可以使用head里的各种对象。
所以我之前纳闷的tail怎么没用下,再这里就派上用场了。
------------------------------------------------
先看调用栈的位置 at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceived(DefaultIoFilterChain.java:943)
这个函数如何定义的?(注意我标粗的$1实际上就是刚才说的内部类对象的标志)
this.nextFilter = new NextFilter() {
...
public void messageReceived(IoSession session, Object message) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextMessageReceived(nextEntry, session, message);
}
...
};
}
具体的函数定义就是这样的。
Entry nextEntry = EntryImpl.this.nextEntry;实际上就是指EntryEmpl tail对象。
然后接着调用callNextMessageReceived,这个函数是不是很眼熟?
因为上面已经调用过了,看到这里我们就很清楚了,通过这种方式来一个一个往下传递
如果有新的逻辑,可以在每个EntryEmpl的IoFilter对象里添加逻辑。
只不过目前实现的逻辑都是空,然后就直接传递给下一个EntryEmpl节点处理了。
--------------------------------------------------------------------接着分析
下一行栈 at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$6(DefaultIoFilterChain.java:538)
这个应该就是内部类相关出现的调用栈函数了,不解释。继续。
at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:542)
这个函数我们也分析过了,忽略。
接下来要注意了:
at org.apache.mina.core.filterchain.DefaultIoFilterChain$TailFilter.messageReceived(DefaultIoFilterChain.java:854)
这个TailFilter可不要小视,所有的文章都在这里了。。。
其实看到这里我们就可以猜测,前面的逻辑主要用来传递,当然可以加入自己的逻辑。’
最后才是大Boss的出场,这个大Boss实际上就是我们main函数里实现的若干函数的调用。‘
好,回来继续分析代码
@Override
public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
AbstractIoSession s = (AbstractIoSession) session;
if (!(message instanceof IoBuffer)) {
s.increaseReadMessages(System.currentTimeMillis()); //统计信息
} else if (!((IoBuffer) message).hasRemaining()) {
s.increaseReadMessages(System.currentTimeMillis());//统计信息
}
// Update the statistics
if (session.getService() instanceof AbstractIoService) {
((AbstractIoService) session.getService()).getStatistics().updateThroughput(System.currentTimeMillis());//统计信息
}
// Propagate the message
try {
session.getHandler().messageReceived(s, message);
} finally {
if (s.getConfig().isUseReadOperation()) {
s.offerReadFuture(message);
}
}
}
亮了,这里我们调用session.getHandler()的messageReceived方法。
那么session的handler是啥对象?
protected AbstractIoSession(IoService service) {
this.service = service;
this.handler = service.getHandler();
看这里,其实最终就是指向了我们main函数里定义的那个类实例。
正如栈所示:at org.apache.mina.example.tcp.perf.TcpServer.messageReceived(TcpServer.java:68)
所以:真想只有1个。
消息发送的机制调用终于解决了。
不过我要提醒一句。
每个消息来的时候,系统都要重新分配内存,这个我觉得是不是可以改进?
毕竟很多开源项目使用了内存池,MINA也可以朝这个方向改进。
MINA目前是直接把这个缓冲区释放了。当然了,JVM会自动回收垃圾。
哎,人艰不拆!