设为首页 收藏本站
查看: 397|回复: 0

[经验分享] 分享Tomcat源码系列三

[复制链接]

尚未签到

发表于 2017-1-23 10:05:10 | 显示全部楼层 |阅读模式
本次讲解一下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()方法被调用。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-332378-1-1.html 上篇帖子: Tomcat数据源配置汇总 下篇帖子: cacti监控tomcat总结 成功导入cacti监控tomcat模板
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表