论坛首页 Java企业应用论坛

深入解析Apache Mina源码(1)——Mina的过滤器机制实现

浏览 28048 次
精华帖 (2) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2012-06-13   最后修改:2012-07-11

1、深入解析Apache Mina源码(1)——Mina的过滤器机制实现

2、深入解析Apache Mina源码(2)——Mina的事件模型

3、深入解析Apache Mina源码(3)——Mina的线程池模型

4、深入解析Apache Mina源码(4)——Mina编解码以及对粘包和断包的处理

 

一、责任链模式的本来面目

Mina 中有一个重要的设计模式-责任链模式,它将此模式成功的应用在了它的过滤器链(IoFilterChain)中。开发过J2EE的童鞋们应该对这个模式比较清楚,在Servlet中我们就可以加入Filter的实现,还有Hibernate中也实现了FilterChain。学习怎么实现责任链模式对于我们对开源软件的学习和以后的工作都会有莫大的帮助。

我们知道计算机系统就是接收信息,进行信息处理,信息输出的过程,那么在这个过程中我们加入过滤器有很多好处,消息经过特定功能的多个过滤器进行逐步处理得到所需要的最终信息,让处理过程透明,责任明晰,方便扩展。

责任链模式的定义我也就不说了,网上一大堆,我的理解是可以把它理解成一个有向链表,消息在这个链表中的某个过滤器进行处理然后再传向下个过滤器,在每个过滤器中都可以处理这些消息,也可以不处理。如图:


责任链模式的类图如下:


其实这里面最核心的就是Handler了,它可是是一个接口或者是一个抽象类,它有对自己的一个引用successor,然后有个处理方法HandleRequest()。因为有了对自己的引用successor所以当本对象不能处理的时候可以转向successor.HandleRequest()方法,这样一个“链”就形成了。

你应该挺羡慕富士.康里面生产苹果手机的工人吧,你平时最喜欢的苹果手机就是他们生产出来的,他们一个人就能把苹果手机生产出来吗?不是的,他们是流水线做业的,OK,流水线就可以看做是责任链模式的体现,工人就是链条上的一员,有的工人组装屏幕,有的工人检查手机,有的工人进行手机的包装等,下面我们就以代码的方式实现:

苹果手机类:

package com.lifanghu.chain;

/**
 * @author lifh
 * @mail wslfh2005@163.com
 * @since 2012-6-12 下午11:20:18
 * @name com.lifanghu.chain.Iphone.java
 * @version 1.0
 */

public class Iphone {

    private String state = "我是一台苹果机器;";

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

}
 

抽象处理接口类:

package com.lifanghu.chain;



/**
 * @author  lifh
 * @mail    wslfh2005@163.com
 * @since   2012-6-12 下午11:23:36
 * @name    com.lifanghu.chain.IWorker.java
 * @version 1.0
 */

public interface IWorker {

    /**
     * 处理方法
     * @param iphone
     * @author lifh
     */
    void handleIphone(Iphone iphone);
    /**
     * 设置下一个处理者
     * @param worker
     * @author lifh
     */
    void setNext(IWorker worker);
}
 

具体处理者:

package com.lifanghu.chain;

/**
 * @author lifh
 * @mail wslfh2005@163.com
 * @since 2012-6-12 下午11:29:46
 * @name com.lifanghu.chain.Worker1.java
 * @version 1.0
 */

public class Worker1 implements IWorker {

    private IWorker next;

    public void handleIphone(Iphone iphone) {
        iphone.setState(iphone.getState() + "我被装了一个黑色的后盖;");
        if (next != null)
            next.handleIphone(iphone);
    }

    public void setNext(IWorker worker) {
        this.next = worker;

    }

}
package com.lifanghu.chain;

/**
 * @author lifh
 * @mail wslfh2005@163.com
 * @since 2012-6-12 下午11:34:32
 * @name com.lifanghu.chain.Worker2.java
 * @version 1.0
 */

public class Worker2 implements IWorker {

    private IWorker next;

    public void handleIphone(Iphone iphone) {
        iphone.setState(iphone.getState() + "我被装了一块电池;");
        if (next != null)
            next.handleIphone(iphone);
    }

    public void setNext(IWorker worker) {
        this.next = worker;
    }
}
package com.lifanghu.chain;

/**
 * @author lifh
 * @mail wslfh2005@163.com
 * @since 2012-6-12 下午11:34:32
 * @name com.lifanghu.chain.Worker3.java
 * @version 1.0
 */

public class Worker3 implements IWorker {

    private IWorker next;

    public void handleIphone(Iphone iphone) {
        iphone.setState(iphone.getState() + "我现在是一台完整的Iphone了。");
        if (next != null)
            next.handleIphone(iphone);
    }

    public void setNext(IWorker worker) {
        this.next = worker;
    }
}
 

客户端调用者:

package com.lifanghu.chain;

/**
 * @author lifh
 * @mail wslfh2005@163.com
 * @since 2012-6-12 下午11:37:27
 * @name com.lifanghu.chain.Client.java
 * @version 1.0
 */

public class Client {

    public static void main(String[] args) {
        IWorker worker1 = new Worker1();
        IWorker worker2 = new Worker2();
        IWorker worker3 = new Worker3();

        worker1.setNext(worker2);
        worker2.setNext(worker3);
        Iphone iphone = new Iphone();
        worker1.handleIphone(iphone);

        System.out.println(iphone.getState());
    }
}
 

输出结果:

 

 写道
我是一台苹果机器;我被装了一个黑色的后盖;我被装了一块电池;我现在是一台完整的Iphone了。
 

 

好了,现在一台苹果就组装完成了,发现了没有,我们的代码比较整洁清新,没有大量的if/else语句,责任清晰明了,调用简单,想要扩展的话只需要再实现IWorker接口即可,这就是使用责任链模式的好处。

二、Mina是怎么实现责任链模式的

上面介绍了纯净的责任链模式,但是在真实的项目中写代码不可能完全照搬,所以多看看开源项目的代码写作方式也许才能真正提高我们的编程能力。就以Mina的过滤器链来看,对这种模式进行了自己的实现,但是道理是相通的,带着责任链模式的理解去看看Mina的实现是怎样的。

先看一下Mina过滤器的类图结构:


从图中我们可以看出Mina对于此模式的实现是相对比较复杂的,其实从它的代码上也可以看出来,当时也是花了好大力气才把它这块看明白,其实主要在于理清思路,抓住核心类,最主要的一个接口IoFilterChain和它的一个内部接口Entry,其中IoFilterChain代表了过滤器的容器,它本身就是一个对象引用形成的链表结构,默认的实现DefaultIoFilterChain其实有对链表头(head)的引用,找到头后就可以顺着头向下找,一直找到尾(tail),Entry是对IoFilterNextFilter的封装整合接口,它属于链表IoFilterChain中的元素。指向当前和下一个过滤器。


EntryImpl 类中包含两个接口,filternextFilter,他们所用的接口是不一样的,至于为什么不用同一个接口,我想可能是因为接口职责单一的原则吧。


 

 

虽然有IoFilterNextFilter两个接口,接口方法都差不多,但最后真正业务的执行者还是IoFilter的实现,IoFilterAdapter做为它的默认实现,完成了适配器的功能,以后的类可以直接继承它而不用实现IoFilter接口,想实现哪个方法只需要覆盖IoFilterAdapter的类的方法即可。NextFilter只起到转发的作用,如消息接收处理方法(messageReceived):

NextFilter的实现:

//消息接收到以后NextFilter的实现会把消息传递给nextEntry去处理。
public void messageReceived(IoSession session, Object message) {
    Entry nextEntry = EntryImpl.this.nextEntry;
    callNextMessageReceived(nextEntry, session, message);
}
 

DefaultIoFilterChain再将消息传递给本FiltermessageReceived方法进行实际的消息接收处理工作:

private void callNextMessageReceived(Entry entry, IoSession session,
        Object message) {
    try {
        IoFilter filter = entry.getFilter();
        NextFilter nextFilter = entry.getNextFilter();
        //本过滤器进行数据处理,完成后再把消息传向下个过滤器
        filter.messageReceived(nextFilter, session,
                message);
    } catch (Throwable e) {
        fireExceptionCaught(e);
    }
}
 

 

当消息处理完成以后,消息就要进入到业务处理IoHandler的实现类中去完成业务的相关操作了。这可以在链尾看到相关业务传递:

@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());
    }

    try {
        // 最后一个filter会进入到handler进行消息处理。
        session.getHandler().messageReceived(s, message);
    } finally {
        if (s.getConfig().isUseReadOperation()) {
            s.offerReadFuture(message);
        }
    }
}
 

 

至此,Mina的链表结构就基本讲完了,其实仔细看看它的代码还是比较容易理解的,可能里面有些细节还需要我们去琢磨。

链表建立了以后,外界是怎样调用的呢?

org.apache.mina.core.filterchain包下我们可以看到类IoFilterEvent,可以看到它实现了基于事件的处理模型,当一个事件(比如接收到消息)发生后会触发相应的事件,进而调用过滤器链的消息处理功能进行消息的处理和转发,这块其实会有线程池的参与完成,会在以后的文章中说明这块。

 

 

public void fire() {
    IoSession session = getSession();
    NextFilter nextFilter = getNextFilter();
    IoEventType type = getType();

    if (DEBUG) {
        LOGGER.debug( "Firing a {} event for session {}",type, session.getId() );
    }

    switch (type) {
    case MESSAGE_RECEIVED:
        //触发消息接收
        Object parameter = getParameter();
        nextFilter.messageReceived(session, parameter);
        break;
 

 

当然也可以直接调用:

 

//触发过滤器的接收消息处理
session.getFilterChain().fireMessageReceived(newBuf);

 

 

 还有一个类DefaultIoFilterChainBuilder,它以用户更易用的角度完成了对过滤器链的封装操作,这里就不细讲了。

总结:本文章主要讲了责任链模式在Mina中的实现,做为一个优秀的框架我们没理由不好好去学习。

每天进步一点点,不做无为的码农。。。。。

2012613日星期三

码农虎虎

http://weibo.com/hurtigf

 

http://www.lifanghu.com/

wslfh2005@163.com

 

  • 大小: 21.3 KB
  • 大小: 22.4 KB
  • 大小: 15.5 KB
  • 大小: 20.8 KB
  • 大小: 12.5 KB
   发表时间:2012-06-14  
不做无为的码农
今天张知识,原来这个就是过滤器链...
0 请登录后投票
   发表时间:2012-06-19  
责任链比较经典的是J2EE中的servlet的过滤器!
0 请登录后投票
   发表时间:2012-06-19  
elan1986 写道
责任链比较经典的是J2EE中的servlet的过滤器!

是的,相当经典。。
0 请登录后投票
   发表时间:2012-06-26  
个人感觉,其实mina2的IoHandler也是利用了类似过滤器链的处理方式,用户可以自定义多个不同的Hanlder来处理不同的业务逻辑,最终全都会被触发。
0 请登录后投票
   发表时间:2012-06-26  
gouerli 写道
个人感觉,其实mina2的IoHandler也是利用了类似过滤器链的处理方式,用户可以自定义多个不同的Hanlder来处理不同的业务逻辑,最终全都会被触发。

IoHandler可以认为是链条的最后一个节点,它没有再向下转发的功能,但是它必须存在。您说的可以自定义多个不同的Hanlder来处理不同的业务逻辑,不知怎么把这多个Hanlder加入进去,好像mina没有提供这样的接口啊。
0 请登录后投票
   发表时间:2012-06-26  
wslfh2005 写道
gouerli 写道
个人感觉,其实mina2的IoHandler也是利用了类似过滤器链的处理方式,用户可以自定义多个不同的Hanlder来处理不同的业务逻辑,最终全都会被触发。

IoHandler可以认为是链条的最后一个节点,它没有再向下转发的功能,但是它必须存在。您说的可以自定义多个不同的Hanlder来处理不同的业务逻辑,不知怎么把这多个Hanlder加入进去,好像mina没有提供这样的接口啊。

    sorry,刚才又去看了下,记混了记混了,mina的handler只能有一个,但是之前看过一个别人写的http server是可以实现多个handler来处理业务逻辑的,实现方法就类似于mina的这个过滤器链。楼主写的不错,介绍的挺清晰。
0 请登录后投票
   发表时间:2012-07-08  
very good!讲的很清楚,最近也在看MINA的源码,读了LZ的文章,受益匪浅。Thanks。期待更好的分享。
0 请登录后投票
   发表时间:2012-07-12  
楼主能不能把java开发中 需要用到Socket,Mina这些网络编程的场景介绍一下?

我认识的人里面,工作中用java做网络编程的基本没有,都是做企业级,互联网开发的,好多人工作了4,5年都没写过scoket,多线程那些东西。
0 请登录后投票
   发表时间:2012-07-12  
edgar108 写道
楼主能不能把java开发中 需要用到Socket,Mina这些网络编程的场景介绍一下?

我认识的人里面,工作中用java做网络编程的基本没有,都是做企业级,互联网开发的,好多人工作了4,5年都没写过scoket,多线程那些东西。

网络编程和多线程等都是底层的开发,这些是基础,刚开始工作的时候以应用为主,但工作时间长了一定要注意这块的学习,对我们优化系统有很大的帮助。
像tomcat等的应用服务器以及各种消息通讯等的软件都要涉及到网络编程啊,就算我们不去实现这些中间件,但我们了解的话对我们的使用有很大的帮助,能及时定位问题等。
目前我主要负责的物联网的项目,需要设备和服务器进行实时通讯,需要解决大并发下的实时通讯问题,所以用到了mina框架。
所以我觉得要想在技术方面提高的话,多线程和网络通讯是绕不开的。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics