`
toking79
  • 浏览: 23024 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Tomcat源码系列3--Tomcat请求处理的流程

阅读更多

本次讲解一下Tomcat请求处理的流程,不当之处还请comment。


一. Tomcat 总体结构
Tomcat采用模块化管理,下面是 Tomcat 的总体结构图:


 
从上图中可以看出 Tomcat 的核心是两个组件:Connector 和 Container。下面是一些概念的介绍。
① Server
一个server代表了整个catalina servlet容器,在Tomcat里面的Server的用处是启动和监听服务端事件(诸如重启、关闭等命令)。
② Service
Service是由一个或多个Connector与一个Engine的组合。
③ Connector
Connector将在某个指定的端口上监听客户的请求,把从socket传递过来的数据,封装成Request,传递给Engine来处理,并从Engine处获得响应并返回给客户。
Tomcat通常会用到两种Connector:
a) Http Connector 在端口8080处侦听来自客户browser的http请求。
b) AJP Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求。

二、请求处理过程解析
1. Connector处理请求
Connector处理请求的流程大致如下:


 
Connector组件启动后,会侦听相关的端口的客户端请求。
(1) 接受一个新的连接请求(org.apache.tomcat.util.net.TcpWorkerThread) 

void runIt(Object[] perThrData){ 
       Socket s = null; 
            try { 
                s = endpoint.acceptSocket();  //获取一个请求 
            } finally { 
                if (endpoint.isRunning()) { 
                    endpoint.tp.runIt(this); 
  // 此处启动另一个TcpWorkerTread去接受其他请求,此线程处理已接受的请求 
                } 
            }                 
      TcpConnection con = null; 
      con = (TcpConnection) perThrData[0]; 
      con.setEndpoint(endpoint); 
      con.setSocket(s);endpoint.getConnectionHandler().processConnection(con,(Object[]) perThrData[1]);     
}

    
(2) 新接收的请求被传到Http11ConnectionHandler中处理。(org.apache.coyote.http11.Http11Protocol.Http11ConnectionHandler) 

void processConnection(TcpConnection connection, Object[] thData){     
    Http11Processor  processor=null; 
    processor=(Http11Processor)thData[Http11Protocol.THREAD_DATA_PROCESSOR];   
    socket=connection.getSocket();                      
    InputStream in = socket.getInputStream();   
    OutputStream out = socket.getOutputStream(); 
    processor.setSocket(socket ); 
    processor.process(in, out);   
//processor是org.apache.coyote.http11.Http11Processor 的 一个实例 
}

 
(3) 在 Http11Processor 中处理 http11 协议相关的信息(org.apache.coyote.http11.Http11Processor)

void process(InputStream input, OutputStream output) throws IOException{ 
        ~~略~~ 
        inputBuffer.setInputStream(input); 
        outputBuffer.setOutputStream(output); 
        inputBuffer.parseHeaders(); 
      //http11 协议头在此方法中被取出 
        adapter.service(request, response);    
      //adapter 是org.apache.catalina.connector.CoyoteAdapter 的 一个实例 
} 

 

接下来的流程交由容器进行处理。
2. 容器处理请求
容器交由Pipeline处理,这个Pipeline里面会放置一些vavle,请求沿着pipeline传递下去并且vavle对其进行相关的处理。比如说日志等,valve还可以自定义,具体需要查看server.xml配置文件。相关类图如下:


 
Tomcat的主要处理组件Engine、Host、Context和Wrapper的实现都会实现Pipeline接口,实际对请求的处理是一个Adpater,Tomcat中Adapter的实现是CoyoteAdapter,因此容器请求处理的入口是CoyoteAdapter的service方法。
1. CoyoteAdapter.service
   --组装好请求处理链
   --StandardEngine. getPipeline().getFirst().invoke(request, response);
       --StandardEngineValve.invoke
2. StandardEngineValve.invoke
   --Host.getPipeline().getFirst().invoke(request, response);
      --StandardHostValve.invoke
3. StandardHostValve.invoke
  --Context. getPipeline().getFirst().invoke(request, response);
     --StandardContextValve.invoke
4. StandardContextValve.invoke
    --ServletRequestListener.requestInitialized
    --Wrapper.getPipeline().getFirst().invoke(request, response);
          --StandardWrapperValve.invoke
    -- ServletRequestListener.requestDestroyed
5. StandardWrapperValve.invoke
    --组装Filter+Servlet
    --处理请求

(1) Connector传来的请求调用CoyoteAdapter.service()方法。(org.apache.catalina.connector.CoyoteAdapter) 

public void service(org.apache.coyote.Request req,    
                    org.apache.coyote.Response res)   
    throws Exception {   
         ~~略~~  
   if (request == null) {  
        request = (Request) connector.createRequest(); 
        request.setCoyoteRequest(req); 
        response = (Response) connector.createResponse(); 
     response.setCoyoteResponse(res); 
     //创建request、response对象   
         ~~略~~   
    }         
    try {    
        if (postParseRequest(req, request, res, response)) {   
connector.getContainer().getPipeline().getFirst().invoke(request, response); 
//此处的Container是StandardEngine对象  
           ~~略~~    
    }   
}

  

(2) 默认StandardEngine的Pipeline会有StandardEngineValve处理单元(参照StandardEngine构造函数)。(org.apache.catalina.core.StandardEngineValve) 

public final void invoke(Request request, Response response)   
    throws IOException, ServletException {     
     // Select the Host to be used for this Request   
  Host host = request.getHost();   
    if (host == null) {   
         response.sendError   
             (HttpServletResponse.SC_BAD_REQUEST,   
             sm.getString("standardEngine.noHost",   
                           request.getServerName()));   
         return;   
     }     
     // Ask this Host to process this request   
     host.getPipeline().getFirst().invoke(request, response);   
   }

   
 
(3) 同样的,StandardHost的Pipeline会有StandardHostValve处理单元。StandardHostValve如何处理请求跟StandardEngineValve类似,接下来请求进入到StandardContextValve.invoke

(4) 同样的,StandardContext的Pipeline会有StandardContextValve处理单元。 
   

public final void invoke(Request request, Response response)   
        throws IOException, ServletException {    
        // Disallow any direct access to resources under WEB-INF or META-INF         MessageBytes requestPathMB = request.getRequestPathMB();   
        if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))   
            || (requestPathMB.equalsIgnoreCase("/META-INF"))   
            || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))   
           || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {   
            String requestURI = request.getDecodedRequestURI();   
            notFound(requestURI, response);   
            return;   
        }     
        // Wait if we are reloading   
        while (context.getPaused()) {   
            try {   
                Thread.sleep(1000);   
            } catch (InterruptedException e) {   
                ;   
            }   
        }     
        // Select the Wrapper to be used for this Request   
        Wrapper wrapper = request.getWrapper();   
        if (wrapper == null) {   
            String requestURI = request.getDecodedRequestURI();   
            notFound(requestURI, response);   
            return;   
        }     
//ServletRequestListener. requestInitialized   
~~略~~   
  
   wrapper.getPipeline().getFirst().invoke(request, response);   
//ServletRequestListener.requestDestroyed   
~~略~~   
     }

   

(5) 同样的,StandardWrapper这个Pipeline会有StandardWrapperValve这个处理单元。在invoke()方法调用Filter的同时,servlet.service()方法也将会被调用。
(org.apache.catalina.core.StandardWrapperValve) 
    

 void invoke(Request request, Response response, ValveContext valveContext) 
                throws IOException, ServletException{ 
         Servlet servlet = null; 
          HttpServletRequest hreq = (HttpServletRequest) request.getRequest();      
//org.apache.catalina.Request被封装成javax.servlet.http.HttpServletRequest. 
          HttpServletResponse hres =(HttpServletResponse) response.getResponse();  
// org.apache.catalina.Response被封装成javax.servlet.http.HttpServletResponse. 
         servlet = wrapper.allocate();       // 装载servlet 
        if ((servlet != null) && (filterChain != null)) { 
           filterChain.doFilter(hreq, hres);                   //调用此servlet的filterchain 
       }

 

(6) 调用servlet的filterchain 处理 request和response
(org.apache.catalina.core.ApplicationFilterChain) 
      

void doFilter(ServletRequest request, ServletResponse response) throws 
                  IOException, ServletException{ 
             ~~略~~ 
           internalDoFilter(request,response); 
             ~~略~~ 
       }

 

(7) 调用internalDoFilter()处理请求。(org.apache.catalina.core.ApplicationFilterChain) 
    

void internalDoFilter(ServletRequest request, ServletResponse response) throws 
                        IOException, ServletException{ 
     // 此处省略filter 处理的代码,filter 被一个一个调用。 
     // 如果http请求的是一个jsp页面, 下面的 servlet 会是 org.apache.jasper.servlet.JspServlet 类的一个实例 
     // 若是 html 页面, 下面的 servlet 会是 org.apache.catalina.servlets.DefaultServlet 类的一个实例 
     if ((request instanceof HttpServletRequest) && 
          (response instanceof HttpServletResponse)) { 
      servlet.service((HttpServletRequest) request, (HttpServletResponse) response); 
        servlet.service(request, response); 
       } else { 
        servlet.service(request, response); 
      } 
    }

 
至此,servlet.service()方法被调用。

 

  • 大小: 10.5 KB
  • 大小: 16.5 KB
  • 大小: 19.9 KB
3
2
分享到:
评论

相关推荐

    tomcat源码,servlet-api源码

    《深入理解Tomcat源码与Servlet-API》 Tomcat,作为Apache软件基金会的顶级项目,是Java Servlet和JavaServer Pages(JSP)的开源Web应用服务器,被广泛应用于中小型企业的Web服务部署。7.0.59版本是Tomcat的一个...

    tomcat-connectors-1.2.48-src

    `mod_jk`负责在HTTPD服务器端接收请求,然后将这些请求转发到Tomcat,而`jk`则在Tomcat端处理这些请求,并返回响应给`mod_jk`,再由`mod_jk`转发给客户端。 2. **版本兼容性** `tomcat-connectors-1.2.48-src`特别...

    Tomcat源码apache-tomcat-8.5.47-src.zip

    在开始学习Tomcat源码之前,首先需要了解一些基本概念。Java Servlet是Java平台上的一个标准接口,用于处理HTTP请求。而JSP则是用于创建动态网页的Java技术,它将业务逻辑和页面展示分离。Tomcat作为Servlet容器,...

    apache-tomcat-7.0.81-src 源码免费下载

    9. **错误处理与日志系统**:Tomcat使用自定义的日志框架,源码中`logging`目录下的类定义了如何记录和处理错误信息。 10. **网络编程**:Tomcat底层使用NIO(非阻塞I/O)和BIO(阻塞I/O)模型,这在`java/org/...

    3-5Tomcat响应请求源码与nio处理请求源码实现.mp4

    3-5Tomcat响应请求源码与nio处理请求源码实现.mp4

    tomcat 源码分析系列文档

    4. "Tomcat源码分析(4)容器处理链接之责任链模式.doc":分析了Tomcat如何利用责任链模式来处理请求,使得请求可以被多个处理器(如过滤器)有序处理。 5. "tomcat加载类的顺序.doc":详细说明了Tomcat加载类的具体...

    apache-tomcat-7.0.62-src和apache-tomcat-6.0.39-src的源码

    这个压缩包包含了两个版本的Tomcat源码:apache-tomcat-7.0.62-src和apache-tomcat-6.0.39-src,这两个版本分别代表了Tomcat在不同时间点的开发状态和技术特性。 首先,让我们从Apache Tomcat 6.0.39源码开始分析。...

    apache-tomcat-9.0.8-src源码资源

    通过对`apache-tomcat-9.0.8-src`源码的深入研究,我们可以了解到Tomcat如何处理网络请求,怎样管理Web应用,以及如何实现各种高级特性。这对于开发者来说是一份宝贵的学习资料,可以帮助他们更好地优化应用程序,...

    tomcat8源码

    Apache Tomcat 8.5.23 源码分析 Apache Tomcat 是一个开源的、免费的Web服务器和Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,...因此,对Tomcat源码的学习对于Java Web开发者来说是至关重要的。

    apache-tomcat-6.0.53-src

    通过研究这些源码,开发者可以深入理解Tomcat的工作流程,例如: - 如何解析HTTP请求并将其分派给相应的Servlet。 - 如何管理会话,包括会话持久化、超时和失效策略。 - 如何处理静态资源和动态内容。 - 如何进行...

    tomcat源码+文档pdf+源码解析

    源码解析部分则是对Tomcat源码的深度剖析,涵盖了关键类和方法的作用、设计模式的运用以及性能优化技巧。这有助于开发者理解Tomcat内部的工作流程,例如,如何处理HTTP请求的生命周期,以及线程池是如何调度和管理的...

    apache-tomcat-6.0.29.zip

    7. **线程池**:Tomcat使用线程池模型处理并发请求,提高性能和响应速度。线程池大小可以在`server.xml`中调整。 8. **安全管理**:Tomcat支持角色基础的访问控制(RBAC),可以设置不同用户的访问权限,通过`...

    tomcat8.0源码+catalina-home.rar

    通过对Catalina Home的源码分析,我们可以深入理解Tomcat如何加载和解析配置,如何管理Web应用,以及如何处理请求和响应。这对于优化应用性能、调试问题以及扩展Tomcat功能都有着极大的帮助。 总的来说,掌握Tomcat...

    jakarta-tomcat-connectors-1.2.15-src.tar.gz

    深入学习jakarta-tomcat-connectors-1.2.15-src源码,可以提升对Tomcat工作流程的理解,包括请求的接收、处理、响应过程,以及如何通过连接器优化服务器性能。这对于进行性能调优、定制化开发或者排查系统问题都至关...

    tomcat源码

    Apache Tomcat源码分析 Apache Tomcat是一款广泛应用的开源Java Servlet容器,它是Java EE Web应用程序的标准实现。Tomcat源码的深入理解对于Java Web开发者来说是至关重要的,它可以帮助我们了解HTTP服务器的工作...

    tomcat-7.0.90-src-源码

    深入Tomcat源码,我们可以学习到以下关键知识点: 1. **Web应用部署**:Tomcat如何解析`WEB-INF/web.xml`配置文件,加载Servlet和Filter,以及如何根据`META-INF/context.xml`设置上下文参数。 2. **生命周期管理*...

    apache-tomcat-9.0.14-src源码

    对于初次接触Tomcat源码的开发者,可以从阅读`src/main/java`目录下的源码开始,重点关注`org.apache.catalina`包下的类,以及`org.apache.coyote`和`org.apache.jasper`等包。同时,`conf/server.xml`是配置整个...

    tomcat8-redis-session共享

    3. **配置Tomcat**:在`$CATALINA_HOME/conf/context.xml`或应用的`WEB-INF/web.xml`中配置Session共享。需要定义一个`Manager`元素,指定使用Redis作为Session存储。配置项可能包括Redis服务器的IP地址、端口、密码...

    tomcat6-server-and-src

    通过分析源码,开发者可以学习到如何遵循Servlet和JSP规范进行服务器端开发,理解Tomcat如何处理请求、管理会话、调度线程等。此外,源码还便于开发者修复已知问题,优化性能,或添加特定的功能。 总之,`tomcat6-...

Global site tag (gtag.js) - Google Analytics