`
fjg0427
  • 浏览: 41996 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

分享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)

Java代码

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)

Java代码

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)

Java代码

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)

Java代码

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)

Java代码

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处理单元。

Java代码

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)

Java代码

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)

Java代码

void doFilter(ServletRequest request, ServletResponse response) throws     
                  IOException, ServletException{     
             ~~略~~     
           internalDoFilter(request,response);     
             ~~略~~     
       }   
(7) 调用internalDoFilter()处理请求。(org.apache.catalina.core.ApplicationFilterChain)

Java代码

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()方法被调用。
分享到:
评论

相关推荐

    apache-tomcat-9.0.0.M22

    2. **Jasper**:Jasper是Tomcat的JSP引擎,负责将JSP页面编译成Java源码,再进一步编译为字节码,最后由Java虚拟机执行。JSP的编译过程可以设置为在首次请求时进行,或者在服务器启动时预先完成。 3. **Coyote**:...

    下载tomcat8.5.707070.zip

    Tomcat是Apache软件基金会Jakarta项目的一部分,它遵循Apache Software License v2.0发布,因此是免费且开放源码的。Tomcat的轻量级特性使其成为小型到中型应用的理想选择,尤其是在资源有限的环境中。 标签“java ...

    管理系统系列--计算机毕业设计源码,JavaWeb项目源码,IT技术分享,毕业设计,课程设计,图书管理系统,贪吃蛇,.zip

    【标题】中的“管理系统系列”指的是一个集合了多种管理系统的项目,这可能包括不同领域的应用,如企业资源规划(ERP)、客户关系管理(CRM)或供应链管理(SCM)。在这个特定的例子中,我们关注的是“图书管理系统...

    Tomcat7.0.67:学习tomcat(7.0.67)

    在下载并解压源码后,用户需要在主目录下创建`lib`、`work`和`logs`这三个文件夹。`lib`文件夹用于存放服务器运行所需的库文件;`work`文件夹是Tomcat处理JSP页面时生成的临时类文件的存储位置;而`logs`文件夹则...

    opencms源码

    10.0.1是OpenCms的一个版本,通常包含一系列改进和新功能。 2. **核心组件** - **内容管理**:OpenCms提供了强大的内容创建、审批和发布流程,包括模板驱动的内容生成,支持XML存储内容。 - **工作流**:系统内置...

    基于springboot的餐饮美食分享平台源码+数据库+项目报告.zip

    - **核心特性**:自动配置、起步依赖、内嵌式Web服务器(如Tomcat、Jetty)。 - **自动配置**:通过`@EnableAutoConfiguration`注解,SpringBoot会根据类路径中的jar包自动配置相关组件。 - **起步依赖**:通过`...

    shell脚本编写和源码

    在IT行业中,Shell脚本是Linux和Unix系统中不可或缺的一部分,它是一种强大的自动化工具,能够帮助用户执行一系列命令,简化日常任务。这个压缩包文件包含了关于shell脚本编写和源码的相关资料,非常适合初学者和有...

    j2ee library项目源码给大家分享

    本篇文章将深入探讨一个名为"library"的J2EE项目源码,该源码分享为我们提供了学习和理解J2EE核心概念的宝贵资源。 首先,我们来看看J2EE的核心组件。J2EE包含以下几个主要部分: 1. **Servlet**:Servlet是Java ...

    基于springboot的IT技术交流和分享平台源码数据库.docx

    - 嵌入式服务器:Spring Boot支持嵌入Tomcat、Jetty或Undertow作为内置服务器,使得应用部署更为简单。 - 简化Maven配置:Spring Boot提供了一系列starter POMs,用于简化Maven依赖管理。 2. **Java语言**: - *...

    springboot学习源码

    在源码中,`run()`方法会进行一系列的初始化工作,包括扫描启动类、加载配置、初始化Bean定义等。 配置文件是SpringBoot的另一个关键部分。SpringBoot支持两种主要的配置文件:`application.properties`和`...

    tomcat sql server mysql 批处理

    在描述中提到的博客链接,虽然具体内容未给出,但我们可以推测博主可能分享了如何在Tomcat环境中配置和运行使用SQL Server或MySQL作为后台数据库的Java Web应用,以及如何编写批处理脚本来自动化这些过程。...

    java web的招聘系统 SSH框架 myeclipse 源码 百度云链接分享

    ### Java Web招聘系统的SSH框架与MyEclipse源码解析 #### 一、Java Web技术概述 Java Web技术是构建Web应用程序的重要工具之一,它利用Java编程语言开发网站应用。Java Web技术的优势在于其跨平台性、安全性以及...

    jsp 在线投票系统 源码

    - **JSTL(JSP Standard Tag Library)**:标准标签库,提供了一系列预定义的标签,用于处理常见任务,如循环、条件判断等。 4. **安全性与优化** - **防止SQL注入**:使用预编译语句或ORM框架(如Hibernate)来...

    课设毕设基于SpringBoot+Vue的地方美食分享网站A LW+PPT+源码可运行.zip

    SpringBoot是Spring框架的简化版,它内置了Tomcat服务器,简化了配置,使得开发者能够快速构建可独立运行的Java应用。在本项目中,SpringBoot作为后端框架,负责处理HTTP请求,提供RESTful API接口,实现数据的增删...

    基于springboot OA自动化办公系统 毕业设计 源码+sql脚本 完整源码

    3. **起步依赖**:提供了一系列“starter”依赖,帮助开发者快速引入所需功能模块,如数据访问、Web服务等。 4. **自动配置**:根据引入的依赖自动配置相关组件,如Spring Data JPA、Spring MVC等。 **数据库MySQL*...

    方立勋 javaweb 源码

    【方立勋 JavaWeb 源码】是一个与JavaWeb开发相关的代码集合,可能是由知名讲师或开发者方立勋创建并分享的。JavaWeb是指使用Java技术进行Web应用程序开发的一系列技术和框架的总称,包括Servlet、JSP、JavaServer ...

    基于SSH的网上订餐系统源码

    3. 订餐全流程管理:从菜单展示、选择菜品、下单支付到订单处理、配送跟踪,这一系列流程都需要被完整地实现。Hibernate将菜品、订单等实体对象与数据库表进行映射,方便数据的持久化存储。 4. 图书管理:虽然标题...

    因酷开源网校系统源码 v2.0.6.zip

    因酷开源网校系统是由北京因酷时代科技有限公司以下简称(因酷教育软件)研发并推出的...tomcat:tomcat 7.0.68已上 因酷开源网校系统截图 账号:demo@inxedu.com 密码:111111 相关阅读 同类推荐:站长常用源码

    web_jsp.rar_jsp_jsp web_web jsp _网站源码

    8. **Web应用部署**:如何将源码打包成WAR文件并在Tomcat或其他Web服务器上部署。 9. **安全性**:学习如何保护网站免受SQL注入、跨站脚本攻击等常见的Web安全问题。 10. **调试和错误处理**:如何在开发过程中...

    java论坛源码jar包

    2. **Servlet容器与EJB服务器兼容**:JForum可以无缝地在各种Servlet容器如Tomcat、Jetty等,以及Enterprise JavaBeans (EJB)服务器如JBoss、GlassFish上运行。这意味着它具有良好的平台兼容性和部署灵活性。 3. **...

Global site tag (gtag.js) - Google Analytics