深入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 {
    @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);
    }

相关文章
|
缓存 分布式计算 API
Spark Netty与Jetty (源码阅读十一)
  spark呢,对Netty API又做了一层封装,那么Netty是什么呢~是个鬼。它基于NIO的服务端客户端框架,具体不再说了,下面开始。   创建了一个线程工厂,生成的线程都给定一个前缀名。      像一般的netty框架一样,创建Netty的EventLoopGroup:      在常用...
1094 0