MINA 2.0.9: MessageReceived事件浅析

为了能够观察此事件,我修改了源码,抛出异常。

   /**

     * {@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(nullnull"head"new HeadFilter());

        tail = new EntryImpl(headnull"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(headsession, 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会自动回收垃圾。

哎,人艰不拆!

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Mina)