在很多架構的設計中,都有類似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);