天天看点

深入Jetty源码之ScopedHandlerc

在很多框架的设计中,都有类似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);

继续阅读