深入Jetty源码之ServletHandler

简介:

概述

ServletHandler继承自ScopedHandler,是Jetty中用于存储所有Filter、FilterMapping、Servlet、ServletMapping的地方,以及用于实现一次请求所对应的Filter链和Servlet执行流程的类。对Servlet的框架实现中,它也被认为是Handler链的末端,因而在它的doHandle()方法中没有调用nextHandle()方法。

ServletHandler的成员

正如前面提到的,ServletHandler是一个用于管理Filter、FilterMapping、Servlet、ServletMapping的容器,因而它需要一下成员用于存储这些它管理的实例:
     private FilterHolder[] _filters= new FilterHolder[0];
     private FilterMapping[] _filterMappings;
    
     private ServletHolder[] _servlets= new ServletHolder[0];
     private ServletMapping[] _servletMappings;
    
     private  final Map<String,FilterHolder> _filterNameMap=  new HashMap<String,FilterHolder>();
     private List<FilterMapping> _filterPathMappings;
     private MultiMap<String> _filterNameMappings;
    
     private  final Map<String,ServletHolder> _servletNameMap= new HashMap<String,ServletHolder>();
     private PathMap _servletPathMap;
其中FilterHolder和ServletHolder分别用于存储Filter、Servlet实例以及其配置信息,即web.xml配置文件中的<filter>、<servlet>的配置信息(参考: Servlet、Filter、Registration的实现 );而FilterMapping和ServletMapping则是FilterName到URL Pattern的mapping信息,以及ServletName到URL Pattern的mapping信息,即web.xml中的<filter-mapping>、<servlet-mapping>信息。

其中FilterMapping包含了一个Filter适用的所有URL Pattern、Servlets、DispatcherType以及对应FilterHolder信息:
     private  int _dispatches=DEFAULT;
     private String _filterName;
     private  transient FilterHolder _holder;
     private String[] _pathSpecs;
     private String[] _servletNames;
它有appliesTo()方法用于判断传入的path和dispatcherType是否符包含当前Filter。对于URL Pattern:*.do=>anything.do, /foo/poo/abc.do, /path/to/*=>/path/to, /path/to/abdc。

而ServletMapping包含了ServletName和其适用的所有URL Pattern,它的URL Pattern的mapping规则和FilterMapping中的规则一样:
     private String _servletName;
     private String[] _pathSpecs;

在管理Filter和FilterMapping中,可以使用FilterHolder、pathSpec、DispatcherType向_filters数组中添加一个FilterHolder,并向_filterMappings数组中添加一个FilterMapping实例;而由该方法引申出来的,可以直接传入Filter实例、Filter类实例、Filter类名,而由方法内部创建对应的FilterHolder实例;DispatcherType可以是一个EnumSet类型的DispatcherType;可以直接添加Filter或FilterMapping或两个同时添加;也可以使用prependFilterMapping将新的FilterMapping添加到数组前。对Servlet和ServletMapping管理也是类似,使用ServletHolder和pathSpec添加_servlets数组和_servletMappings数组,并引申出Servlet可以是实例、Servlet类名、Servlet类实例,而由内部创建ServletHolder实例;也可以单独的添加ServletHolder或ServletMapping实例。

在ServletHandler中还有_filterNameMap和_servletNameMap实例用于存储FilterName到FilterHolder以及ServletName到ServletHolder的映射,它在每次_filters、_servlets数组更新时都会随着更新,并且在doStart方法中也会再更新一次;另外对Filter还有_filterPathMapping用于存储所有FilterMapping的一个List,_filterNameMapping用于存储ServletName到多个FilterMapping的MultiMap,对Servlet中也有_servletPathMap,包含pathSpec到ServletHolder的PathMap,他们在每次_filterMappings、_servletMappings更新时以及doStart方法中都会被更新。而在start时也会start所有的FilterHolder和ServletHolder,对所有FilterHolder的start按其定义顺序进行,而对ServletHolder的start,则按其InitOrder排序。

doScope方法实现

doScope方法用于准备执行环境,其实现逻辑为:如果传入的target不是ServletName(即以"/"开头,表示它为Path),则使用该target从_servletPathMap中找到对应的ServletHolder,并计算出当前的ServletPath和PathInfo,如果时INCLUDE类型的Dispatch,设置Request的javax.servlet.include.serlvet_path,javax.servlet.include.path_info属性为计算出来的值,否则设置Request的ServletPath和PathInfo的值为计算出的值;对target为ServletName,ServletHolder的实例从_servletNameMap字段中查找。然后将当前找到的ServletHolder作为UserIdentityScope设置到Request中,以及设置org.eclipse.multipartConfig属性为ServletHolder中的MultipartConfig实例。在刚方法退出时,将UserIdentityScope、ServletPath、PathInfo还原回原来的值。

doHandle方法实现

doHandle方法用于真正实现执行逻辑:它首先通过target找到FilterChain实例,对于target为path时,它遍历整个_filterPathMapping的列表,选出所有符合pathInContext的FilterHolder数组,以及从_filterNameMappings中找出所有ServletHolder中存储的ServletName对应的FilterMapping并且DispatcherType相符合的FilterMapping数组,以及注册的ServletName为"*"的FilterMapping且DispatcherType相符的FilterMapping数组,合并这些数组,并一同用Request、ServletHolder创建FilterChain实例;对target为ServletName时,只需要查找_filterNameMapping字段中的FilterMapping。如果没有FilterHolder实例,则向客户端发送404 Not Found响应;否则如果FilterChain实例不为null,调用其doFilter方法,传入ServletRequest和ServletResponse参数,在FilterChain的doFilter方法中它回一次遍历Filter的doFilter方法,直到最后调用ServletHolder的handle方法;否则,直接调用ServletHolder的handle方法。

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