上善若水
In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
posts - 146,comments - 147,trackbacks - 0

概述

在很多框架的设计中,都有类似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 {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            // Add user customized logic here when request come into the channel
            chain.doFilter(request, response);
        } finally {
            // 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.handle()
|-A.doScope()
|--B.doScope()
|---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);
        else 
            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);
            }
        }

        @Override
        public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            try {
                _history.append(">W").append(_name);
                super.nextHandle(target,baseRequest,request,response);
            } finally {
                _history.append("<W").append(_name);
            }
        }
    }
然后有非ScopedHandler的实现:
    private class OtherHandler extends HandlerWrapper {
        private final String _name;

        private OtherHandler(String name) {
            _name=name;
        }

        @Override
        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            try {
                _history.append(">H").append(_name);
                super.handle(target,baseRequest,request, response);
            } finally {
                _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);
    }
posted on 2014-05-07 23:49 DLevin 阅读(1397) 评论(3)  编辑  收藏 所属分类: Jetty

FeedBack:
# re: 深入Jetty源码之ScopedHandler
2014-05-08 08:25 | 金利锁业
支持博主分享啊  回复  更多评论
  
# re: 深入Jetty源码之ScopedHandler
2014-05-08 08:52 | regale
请问_history是怎么传进去的?  回复  更多评论
  
# re: 深入Jetty源码之ScopedHandler
2014-05-08 09:17 | DLevin
代码没有贴全,TestHandler和OtherHandler都是Test类中的内部类,而_history是Test类的成员@regale
  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: