`

jetty的ServletHandler分析(servlet最终调用前的一些流程)

 
阅读更多

前面很多文章都提到过ServletHandler这种类型,它在整个http的处理中所占的位置如下:

(1)connector -> (2)server->(3)contextHandlerCollection->(4)WebAppContext->(5)ServletHandler->(6)Servlet

从上面整个http的处理过程来看,ServletHandler应该算得上是最接近用户定义的servlet的了。。。

一般情况下context收到http请求之后,这个请求最终都会直接交到servletHandler来处理,因此它也需要负责对http请求的path进行处理,从而才能将这个http请求交给正确的servlet。。。。

 

好了,先来看看ServletHandler的一些重要的属性的定义吧:

[java] view plaincopy
 
  1. private ContextHandler _contextHandler;   //这个servlet所属的contextHandler  
  2. private ContextHandler.SContext _servletContext;  //当前这个context的servletcontext  
  3. private FilterHolder[] _filters;   //filter数组  
  4. private FilterMapping[] _filterMappings;  //xml中的filter的map信息  
  5. private boolean _filterChainsCached=true;  
  6. private int _maxFilterChainsCacheSize=1000;  
  7. private boolean _startWithUnavailable=true;  
  8.   
  9. private ServletHolder[] _servlets;   //servletholder数组,一般情况下用户定义的servlet都会被servletholder包装一下  
  10. private ServletMapping[] _servletMappings;   //用于保存从xml中读取出来的servlet的map信息  
  11.   
  12. private transient Map _filterNameMap= new HashMap();    //filter的name对应  
  13. private transient List _filterPathMappings;   //将filter与特定的path对应起来  
  14. private transient MultiMap _filterNameMappings;  //servlet的name与filter的对应,有的filter可能会指定特定的servlet  
  15.   
  16. private transient Map _servletNameMap=new HashMap();   //servlet与名字进行对应  
  17. private transient PathMap _servletPathMap;   //pathmap,这个很重要,当请求来了之后,就会通过它来匹配出合适的servlet来处理  
  18.   
  19. protected transient HashMap _chainCache[];   //请求访问path与fitlerchain的缓存,防止每次都要创建  

 

 

这里最为重要的一个属性应该就是servletPathMap了吧,我们在web.xml文件中会定义许多servlet,最后都会通过  <servlet-mapping> 元素将某个servlet与一个或者多个path对应起来。。。而这最终的对应关系都会在servletPathMap里面。。。另外还有许多其他的属性,具体他们是干什么的,应该注释就说的很清楚了吧。。。

那么接下来我们来看看ServletHandler的doStart方法吧:

[java] view plaincopy
 
  1. //servlethandler的启动过程  
  2. protected synchronized void doStart()  
  3.     throws Exception {  
  4.     _servletContext=ContextHandler.getCurrentContext();  //获取当前的servletcontext  
  5.     _contextHandler=_servletContext==null?null:_servletContext.getContextHandler(); //保存其所属的contextHandler  
  6.   
  7.     updateNameMappings();   //名字对应map的更新,也就是我们在xml文件中定义的servlet名字与servletholder对象的对应,当然这里还有filter  
  8.     updateMappings();  //处理xml文件中定义的mapping信息,这里最重要要做的事情就是更新pathMap  
  9.       
  10.     if(_filterChainsCached)  //这个数组的构建比较奇怪啊  
  11.         _chainCache=     new HashMap[]{null,new HashMap(),new HashMap(),null,new HashMap(),null,null,null,new HashMap()};  
  12.   
  13.     super.doStart();  
  14.       
  15.     if (_contextHandler==null || !(_contextHandler instanceof Context)) {//一般情况下不会调用,除非直接在server的handler就弄成了ServletHandr,在context的start后会在外面调用init方法  
  16.         initialize();  //这个方法用于从classLoader里面载入servlet的calss文件,并且需要的话,会初始化这个servlet对象  
  17.     }  
  18. }     

 

 

代码还算比较的简洁吧,因为要做的事情都调用其他的方法来处理了,这里主要就是要建立两个map,首先是name与filterHolder或者servletHolder的对应关系,接着是path与fitler或者servlet的对应关系。。。。

那么先来看看updateNameMappings方法吧:

[java] view plaincopy
 
  1. //更新与名字关联的map,filter的namemap与servlet的namemap  
  2. protected synchronized void updateNameMappings() {     
  3.     _filterNameMap.clear();  //清空filter的name关联map  
  4.     if (_filters!=null) {     //从xml文件中定义的filter会保存在这个数组中  
  5.         for (int i=0;i<_filters.length;i++) {  //遍历所有定义的filter  
  6.             _filterNameMap.put(_filters[i].getName(),_filters[i]);  //这里key是名字,value是filterHolder  
  7.             _filters[i].setServletHandler(this);  
  8.         }  
  9.     }  
  10.   
  11.     _servletNameMap.clear();  //清空servlet的与name关联的map  
  12.     if (_servlets!=null) {     
  13.         for (int i=0;i<_servlets.length;i++) {  //遍历所有定义的servlet  
  14.             _servletNameMap.put(_servlets[i].getName(),_servlets[i]);  
  15.             _servlets[i].setServletHandler(this);  
  16.         }  
  17.     }  
  18. }  

 

 

这段代码应该算是很简单的吧,这里首先遍历filter数组,里面保存了在启动的时候从默认以及用户定义的xml文件中定义的所有的filter,当然它被包装成了filterHolder,然后将他们放到map里面,key是这个filter的名字,value就是当前这个filterHolder了。。。下面对servlet的处理都是一样的。。。

那么接下来来看看updateMappings方法吧:

[java] view plaincopy
 
  1. //这里主要是是设置pathmap  
  2. protected synchronized void updateMappings() {     
  3.     if (_filterMappings==null) {  
  4.         _filterPathMappings=null;  
  5.         _filterNameMappings=null;  
  6.     } else {  
  7.         _filterPathMappings=new ArrayList();  
  8.         _filterNameMappings=new MultiMap();  
  9.         //遍历xml中定义的所有的fitler的map信息  
  10.         for (int i=0;i<_filterMappings.length;i++)  {  
  11.             //获取相应的filterholder  
  12.             FilterHolder filter_holder = (FilterHolder)_filterNameMap.get(_filterMappings[i].getFilterName());  
  13.             if (filter_holder==null)  
  14.                 throw new IllegalStateException("No filter named "+_filterMappings[i].getFilterName());  
  15.             _filterMappings[i].setFilterHolder(filter_holder);      
  16.             if (_filterMappings[i].getPathSpecs()!=null)  
  17.                 _filterPathMappings.add(_filterMappings[i]);  //如果需要path,那么将其放到pathMap里面去  
  18.               
  19.             //有的filter指定了servlet,那么需要将servlet的名字与当前的filterHolder对应  
  20.             if (_filterMappings[i].getServletNames()!=null) {  
  21.                 String[] names=_filterMappings[i].getServletNames();  
  22.                 for (int j=0;j<names.length;j++)  
  23.                 {  
  24.                     if (names[j]!=null)  
  25.                         _filterNameMappings.add(names[j], _filterMappings[i]);    //这里key是servlet的名字  
  26.                 }  
  27.             }  
  28.         }  
  29.     }  
  30.   
  31.     //将path与servletholder对应起来  
  32.     if (_servletMappings==null || _servletNameMap==null) {  
  33.         _servletPathMap=null;  
  34.     } else {  
  35.         PathMap pm = new PathMap();  //创建pathmap  
  36.           
  37.         //遍历所有从xml文件中读出的servlet的map信息,保存的是用户定义的servlet与其map的信息,一个servlet可能会map到多个path  
  38.         for (int i=0;i<_servletMappings.length;i++) {  
  39.             //获取servlethodler  
  40.             ServletHolder servlet_holder = (ServletHolder)_servletNameMap.get(_servletMappings[i].getServletName());  
  41.             if (servlet_holder==null) {  
  42.                 throw new IllegalStateException("No such servlet: "+_servletMappings[i].getServletName());  
  43.             } else if (_servletMappings[i].getPathSpecs()!=null) {    
  44.                 String[] pathSpecs = _servletMappings[i].getPathSpecs();  //获取这个servlet指定的要处理的path  
  45.                 for (int j=0;j<pathSpecs.length;j++)  
  46.                     if (pathSpecs[j]!=null)  
  47.                         pm.put(pathSpecs[j],servlet_holder);  //将path与servletholder放到pahtmap里面去  
  48.             }  
  49.         }  
  50.           
  51.         _servletPathMap=pm;  
  52.     }  
  53.       
  54.     if (Log.isDebugEnabled())  {  
  55.         Log.debug("filterNameMap="+_filterNameMap);  
  56.         Log.debug("pathFilters="+_filterPathMappings);  
  57.         Log.debug("servletFilterMap="+_filterNameMappings);  
  58.         Log.debug("servletPathMap="+_servletPathMap);  
  59.         Log.debug("servletNameMap="+_servletNameMap);  
  60.     }     
  61.     try {    
  62.         if (isStarted()) {  
  63.             initialize();  
  64.         }  
  65.     } catch (Exception e)  {  
  66.         throw new RuntimeException(e);  
  67.     }  
  68. }  

 

 

代码也还算是比较的简单吧,这里遍历的对象是我们在xml配置文件中定义的一些mapping项,然后进行相应的处理。。

例如,对于filter,我们可以定义它处理的path,也可以为其指定特定的servlet,因此在filter这里需要维护filterPathMapping与filterNameMapping两个对应关系。。。

对于servlet的处理就稍微要简单些了,主需要处理与path相关的对应就可以了,将其放到pathMap里面。。。

 

[java] view plaincopy
 
  1. //这里的target就是处理过的了,去掉了前面的contextPath,然后删去了最后的参数  
  2. //这里会用target来匹配住合适的servlet来处理  
  3. public void handle(String target, HttpServletRequest request,HttpServletResponse response, int type)  
  4.      throws IOException, ServletException {  
  5.     if (!isStarted())  
  6.         return;  
  7.   
  8.     // Get the base requests  
  9.     //其实这里获取base_request一般情况下就是当前的request  
  10.     final Request base_request=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();  
  11.     //获取上次这个request的处理的一些信息,为了待会处理失败之后可以恢复现场  
  12.     final String old_servlet_name=base_request.getServletName();  //上一次request处理的servlet的名字(要知道request对象也是会复用的)  
  13.     final String old_servlet_path=base_request.getServletPath();  
  14.     final String old_path_info=base_request.getPathInfo();  
  15.     final Map old_role_map=base_request.getRoleMap();  
  16.       
  17.     try {  
  18.         ServletHolder servlet_holder=null;  //待会用这个指向找出来的servletHolder  
  19.         FilterChain chain=null;  
  20.           
  21.         // find the servlet  
  22.         if (target.startsWith("/")) {    
  23.             PathMap.Entry entry=getHolderEntry(target);   //通过targer的匹配,找出合适的servletholder  
  24.             if (entry!=null) { //如果可以找到合适的servlet    
  25.                 servlet_holder = (ServletHolder)entry.getValue();   //获取相应的servletHodler  
  26.                 base_request.setServletName(servlet_holder.getName());  //设置servlet的一些基本信息  
  27.                 base_request.setRoleMap(servlet_holder.getRoleMap());  
  28.                 if(Log.isDebugEnabled())Log.debug("servlet="+servlet_holder);  
  29.                   
  30.                 String servlet_path_spec=(String)entry.getKey();   //获取匹配到的servlet的path信息  
  31.                 String servlet_path=entry.getMapped()!=null?entry.getMapped():PathMap.pathMatch(servlet_path_spec,target);  
  32.                 String path_info=PathMap.pathInfo(servlet_path_spec,target);  
  33.                   
  34.                 if (type==INCLUDE) {  
  35.                     base_request.setAttribute(Dispatcher.__INCLUDE_SERVLET_PATH,servlet_path);  
  36.                     base_request.setAttribute(Dispatcher.__INCLUDE_PATH_INFO, path_info);  
  37.                 } else {  
  38.                     base_request.setServletPath(servlet_path);  
  39.                     base_request.setPathInfo(path_info);  
  40.                 }  
  41.                   
  42.                 if (servlet_holder!=null && _filterMappings!=null && _filterMappings.length>0) {  
  43.                     chain=getFilterChain(type, target, servlet_holder);  //组装一个filter链,待会处理会先调用filter,然后在调用servlet  
  44.                 }  
  45.             }        
  46.         } else { //如果targer不是以“/”开始的,那么表示不是以path来匹配的,所以要用名字来找servlet  
  47.             servlet_holder=(ServletHolder)_servletNameMap.get(target);  //通过名字来寻找servletholder  
  48.             if (servlet_holder!=null && _filterMappings!=null && _filterMappings.length>0)  
  49.             {  
  50.                 base_request.setServletName(servlet_holder.getName());  
  51.                 chain=getFilterChain(type, null,servlet_holder);  //构成链  
  52.             }  
  53.         }  
  54.   
  55.         if (Log.isDebugEnabled())  {  
  56.             Log.debug("chain="+chain);  
  57.             Log.debug("servlet holder="+servlet_holder);  
  58.         }  
  59.   
  60.         // Do the filter/handling thang  
  61.         //先进行filter的操作,然后处理http请求  
  62.         if (servlet_holder!=null)  
  63.         {  
  64.             base_request.setHandled(true);  //这里设置一个标志位,表示这个http请求已经处理过了  
  65.             if (chain!=null) {   //如果有filter链,那么还需要先从filter来开始执行  
  66.                 chain.doFilter(request, response);  
  67.             } else {  //如果没有的话,那么直接调用servletholder的handle方法来处理就好了,这期其实也就是调用实际的servlet的service方法  
  68.                 servlet_holder.handle(request,response);  
  69.             }  
  70.         } else {  
  71.             notFound(request, response);  //这里表示找不到处理  
  72.         }  
  73.     }  



 

代码应该很容易就能够看明白吧,这里首先需要根据target来获取相应的servletHolder,而且然后还要获取需要执行的filter,将他们构成链条,在filter执行完了以后再经由servlet来处理这次http请求。。。。

这里通过target来获取相应的servletholder调用的是getHolderEntry方法,其实这个方法的定义也非常的简单,无非就是直接从前面提到的pathMap里面获得相应的servletHolder就好了。。。

 

好了,这篇文章之后,应该对jetty的整个http的处理流程就已经很清楚了。。。。

可能以后关于jetty的文章都是这种比较细节的了吧,毕竟整体的东西都差不多了。

分享到:
评论

相关推荐

    JSP项目集成jetty服务器+servlet 3.0 demo

    **JSP项目集成Jetty服务器与Servlet 3.0演示** 在Java Web开发中,`JSP(JavaServer Pages)`是一种动态网页技术,它允许开发者将Java代码嵌入到HTML页面中,以实现服务器端的逻辑处理。而`Servlet`是Java EE中的一...

    Jetty 9 Servlet容器

    Jetty 9是一款轻量级、高性能且开源的Servlet容器,它主要负责处理基于Java Servlet规范的应用程序。作为Java服务的一部分,Jetty9为开发者提供了高效、稳定且灵活的平台来部署和运行Web应用程序。 首先,Jetty 9...

    jetty-servlet-9.3.19.v20170502-API文档-中英对照版.zip

    赠送jar包:jetty-servlet-9.3.19.v20170502.jar; 赠送原API文档:jetty-servlet-9.3.19.v20170502-javadoc.jar; 赠送源代码:jetty-servlet-9.3.19.v20170502-sources.jar; 赠送Maven依赖信息文件:jetty-...

    jetty servlet容器

    Jetty 是一个开源的servlet容器,它为基于Java的web容器,例如JSP和servlet提供运行环境。Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布。开发人员可以将Jetty容器实例化成一个对象,可以迅速为一些独立...

    jetty-servlet-8.1.8.v20121106-API文档-中英对照版.zip

    赠送jar包:jetty-servlet-8.1.8.v20121106.jar; 赠送原API文档:jetty-servlet-8.1.8.v20121106-javadoc.jar; 赠送源代码:jetty-servlet-8.1.8.v20121106-sources.jar; 赠送Maven依赖信息文件:jetty-servlet-...

    jetty-servlet-9.2.10.v20150310.jar

    solr jetty-servlet-9.2.10.v20150310.jar

    jetty-servlet-8.1.8.v20121106-API文档-中文版.zip

    赠送jar包:jetty-servlet-8.1.8.v20121106.jar; 赠送原API文档:jetty-servlet-8.1.8.v20121106-javadoc.jar; 赠送源代码:jetty-servlet-8.1.8.v20121106-sources.jar; 赠送Maven依赖信息文件:jetty-servlet-...

    基于Jetty+Servlet+Jsp+MySQL+MyBatis技术实现的简单博客系统

    内容概要:本博客系统主要使用Jetty技术+Servlet技术+Jsp技术+BootStrap前端框架+wangEditor富文本编辑器+MySQL数据库+MyBatis持久层,通过对该系统的设计,可以在实践过程中掌握相关基础知识,如对三层架构开发模式...

    jetty-servlet-9.3.19.v20170502-API文档-中文版.zip

    赠送jar包:jetty-servlet-9.3.19.v20170502.jar; 赠送原API文档:jetty-servlet-9.3.19.v20170502-javadoc.jar; 赠送源代码:jetty-servlet-9.3.19.v20170502-sources.jar; 赠送Maven依赖信息文件:jetty-...

    Jetty源码分析.pdf

    - 通过对Jetty源码的深入分析,可以发现其设计的核心理念在于简化Web应用的部署流程,同时保证高性能与灵活性。无论是对于初学者还是有经验的开发者来说,Jetty都提供了强大的工具与框架支持,帮助他们快速搭建起...

    Jetty Servlet+ HttpClient 制作的 Java HttpProxy

    【Java HttpProxy实现详解——基于Jetty Servlet与HttpClient】 在Java开发中,有时我们需要创建一个HTTP代理服务器,以便转发客户端的HTTP请求到指定的目标服务器。本文将深入探讨如何使用Jetty Servlet容器和...

    jetty的http服务流程分析

    `RequestHandler.headerComplete()`方法处理完请求头后,调用事件处理器(EventHandler)处理请求,最终请求被分派给`Server`中的`_handler`对象,这通常是Servlet或其他处理器,它们在配置文件中定义并通过反射机制...

    jetty 8及依赖包

    学习Jetty 8,你可以深入理解Web服务器的内部机制,包括线程模型、请求处理流程、以及如何利用Servlet和WebSocket构建现代Web应用。通过分析源代码和实验,你可以了解到如何自定义配置Jetty以适应特定的应用需求,...

    jetty的main启动代码及相关jar包

    jetty的main启动代码及相关jar包: jetty-6.1.26.jar、jetty-util-6.1.26.jar为jetty相关jar包。 jasper-el.jar、jasper-jdt.jar、jasper.jar为jsp页面解析编译相关jar包。 jsp-api.jar为jstl相关jar包 tomcat-juli....

    基于Jetty嵌入的Servlet封装HTTP服务框架设计源码

    本项目为基于Servlet封装的HTTP服务框架设计源码,采用Java语言编写,并包含794个文件,涵盖784个Java源代码文件、3个属性配置文件、2个Markdown文件、1个...该框架以Jetty作为Web容器进行嵌入,便于项目集成和使用。

    javax.servlet-3.0.0.v201112011016-API文档-中文版.zip

    标签:eclipse、jetty、orbit、javax、servlet、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和...

    i-jetty源码

    3. **Handler**:查看`Handler`接口和其实现,如`ContextHandler`和`ServletHandler`,它们处理HTTP请求并调用对应的Servlet。 4. **Servlet**:分析Servlet的相关代码,了解如何注册和管理Servlet,以及Servlet...

    Jetty java程序指定一个端口,开通一个TCP服务

    Jetty是一款轻量级、高性能的Java Web服务器和Servlet容器,它允许开发者在Java应用程序中直接启动HTTP服务器和Servlet容器,而无需通过完整的Java EE应用服务器。本篇将详细讲解如何使用Jetty来指定一个端口,开通...

    javax.servlet-3.0.0.v201112011016-API文档-中英对照版.zip

    标签:eclipse、jetty、orbit、javax、servlet、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释...

    jetty6 嵌入式使用

    2. **引入Starter类**:Jetty 6提供了一些启动类,例如`org.mortbay.jetty.Server`,你可以通过实例化这个类并调用其start方法来启动服务器。示例代码如下: ```java import org.mortbay.jetty.Server; import ...

Global site tag (gtag.js) - Google Analytics