在很多框架的设计中,都有类似channel链的设计,类似decorator模式或chain of responsibility模式,可以向这个channel注册不同的handler,用户请求可以穿越这个由多个handler组成的channel,执行响应的切面逻辑,在最后一个handler或者另一个processor处理用于自定义的业务逻辑,然后生成的响应可以逆着方向从这个channel回来。structs2中的interceptor、servlet中filter都采用这种设计。这种设计为面向切面编程提供了遍历,然而目前的handler设计更多的像是chain of responsibility模式,它的处理逻辑只能从链头走到链尾,而没有返回的路程。引入scopedhandler的目的就是用于解决这个问题。
structs2中interceptor实现使用传入actioninvaction来调用channel中的后继interceptor:
public class myinterceptor extends abstractinterceptor {
@override
public string intercept(actioninvocation ai) throws exception {
try {
// add user customized logic here when request come into the channel
return ai.invoke();
} finally {
// add user customized logic here when response pass out across the channel
}
}
}
类似的,servlet中的filter实现也是使用filterchain来调用channel中后继的filter:
public class myfilter implements filter {
public void dofilter(servletrequest request, servletresponse response, filterchain chain) throws ioexception, servletexception {
// add user customized logic here when request come into the channel
chain.dofilter(request, response);
// add user customized logic here when response pass out across the channel
}
}
scopedhandler采用了不同的实现方式,首先它继承自handlerwrapper,因而它使用handlerwrapper中的handler字段来构建handler链,然而并不是所有的handler都是scopedhandler,因而scopedhandler内部还定义了_nextscope字段用于创建在这条handler链表中的scopedhandler链表,以及_outerscope字段用于将自己始终和这个scopedhandler链表中的最外层scopedhandler相连,对这个scopedhandler的最外层列表,其_outscope字段为null。而scopedhandler要实现的行为是,假设a、b、c都是scopedhandler,并且它们组成链表:a->b->c,那么当调用a.handle()方法时的调用堆栈是:
a.handle()
|-a.doscope()
|--b.doscope()
|----c.doscope()
|-----a.dohandle()
|------b.dohandle()
|-------c.dohandle()
而如果a、b是scopedhandler,x、y是其他的handler,并且它们组成链表:a->x->b->y,那么当调用a.handle()方法时的调用栈是:
|---a.dohandle()
|----x.handle()
|-----b.dohandle()
|------y.handle()
这种行为主要用于servlet框架的实现,它可以保证在doscope()方法中做一些初始化工作,并且配置环境,而在后继调用中都可以使用这些配置好的环境,并且dohandle()的顺序还是使用原来定义的handler链表顺序,即使有些handler并不是scopedhandler。
在实现中,其handler链表由handlerwrapper构建,在dostart()方法中计算_nextscope字段以及_outerscope字段,在handle()方法中,如果_outerscope为null,则调用doscope()方法,否则调用dohandle()方法:
@override
public final void handle(string target, request baserequest, httpservletrequest request, httpservletresponse response) throws ioexception, servletexception
{
if (_outerscope==null)
doscope(target,baserequest,request, response);
else
dohandle(target,baserequest,request, response);
在执行完doscope()方法后,调用nextscope()方法,该方法顺着_nextscope链表走,直到尽头,后调用dohandle()方法:
public final void nextscope(string target, request baserequest, httpservletrequest request, httpservletresponse response) throws ioexception, servletexception
if (_nextscope!=null)
_nextscope.doscope(target,baserequest,request, response);
else if (_outerscope!=null)
_outerscope.dohandle(target,baserequest,request, response);
而dohandle()方法在完成是调用nexthandle()方法,它也沿着_nextscope链表走,只要_nextscope和_handler相同,则调用其dohandle()方法,但是如果_nextscope和_handler不同,则调用_handler中的handle()方法,用于处理在scopedhandler链表中插入非scopedhandler的情况:
public final void nexthandle(string target, final request baserequest, httpservletrequest request, httpservletresponse response) throws ioexception, servletexception
if (_nextscope!=null && _nextscope==_handler)
_nextscope.dohandle(target,baserequest,request, response);
else if (_handler!=null)
_handler.handle(target,baserequest, request, response);
在scopedhandler的测试用例中给出了一个非常好的例子。首先有一个testhandler继承自scopedhandler:
private class testhandler extends scopedhandler {
private final string _name;
private testhandler(string name) {
_name=name;
@override
public void doscope(string target, request baserequest, httpservletrequest request, httpservletresponse response) throws ioexception, servletexception {
try {
_history.append(">s").append(_name);
super.nextscope(target,baserequest,request, response);
} finally {
_history.append("<s").append(_name);
}
public void dohandle(string target, request baserequest, httpservletrequest request, httpservletresponse response) throws ioexception, servletexception {
_history.append(">w").append(_name);
super.nexthandle(target,baserequest,request,response);
_history.append("<w").append(_name);
然后有非scopedhandler的实现:
private class otherhandler extends handlerwrapper {
private otherhandler(string name) {
public void handle(string target, request baserequest, httpservletrequest request, httpservletresponse response) throws ioexception, servletexception {
_history.append(">h").append(_name);
super.handle(target,baserequest,request, response);
_history.append("<h").append(_name);
查看一下test case的执行结果:
@test
public void testdouble() throws exception
testhandler handler0 = new testhandler("0");
otherhandler handlera = new otherhandler("a");
testhandler handler1 = new testhandler("1");
otherhandler handlerb = new otherhandler("b");
handler0.sethandler(handlera);
handlera.sethandler(handler1);
handler1.sethandler(handlerb);
handler0.start();
handler0.handle("target",null,null,null);
handler0.stop();
string history=_history.tostring();
system.err.println(history);
assertequals(">s0>s1>w0>ha>w1>hb<hb<w1<ha<w0<s1<s0",history);