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对于此模式的实现是相对比较复杂的,其实从它的代码上也可以看出来,当时也是花了好大力气才把它这块看明白,其实主要在于理清思路,抓住核心类,最主要的一个接口IoFilterChain和它的一个内部接口Entry,其中IoFilterChain代表了过滤器的容器,它本身就是一个对象引用形成的链表结构,默认的实现DefaultIoFilterChain其实有对链表头(head)的引用,找到头后就可以顺着头向下找,一直找到尾(tail),Entry是对IoFilter和NextFilter的封装整合接口,它属于链表IoFilterChain中的元素。指向当前和下一个过滤器。
EntryImpl?类中包含两个接口,filter和nextFilter,他们所用的接口是不一样的,至于为什么不用同一个接口,我想可能是因为接口职责单一的原则吧。
?
?虽然有IoFilter和NextFilter两个接口,接口方法都差不多,但最后真正业务的执行者还是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再将消息传递给本Filter的messageReceived方法进行实际的消息接收处理工作:
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中的实现,做为一个优秀的框架我们没理由不好好去学习。
每天进步一点点,不做无为的码农。。。。。
2012年6月13日星期三
码农虎虎
http://weibo.com/hurtigf
?
http://www.lifanghu.com/
wslfh2005@163.com