• Tomcat 源码分析 (Tomcat请求处理流程) (五)


    0.前记

    本章主要内容为在请求转交给Coyote适配器后的流程分析

    紧接上文中请求交由Processor处理.

    CoyoteAdapter.service()
    此时在service方法中会调用CoyoteAdapter.service(),至此请求就即将被发送给Engine引擎.

     //获取Coyote适配器,并调用其service方法
    getAdapter().service(request, response); 
    
    • 1
    • 2

    在这里插入图片描述

    1.请求处理流程分析

    CoyoteAdapter.service()

    在这里插入图片描述

    这里先将CoyoteRequest转换为HttpServletRequest, 然后HttpServletRequest里设置CoyoteRequest

    然后就是一系列的invoke方法

    在这里插入图片描述

    在这里插入图片描述

    1. 请求被Connector组件接收,创建RequestResponse对象。

    2. ConnectorRequestResponse交给Container,先通过Enginepipeline组件流经内部的每个Valve

    3. 请求流转到Hostpipeline组件中,并且经过内部Valve的过滤。

    4. 请求流转到Context的pipeline组件中,并且经过内部的Valve的过滤。

    5. 请求流转到Wrapperpipeline组件中,并且经过内部的Valve的过滤。

    6. Wrapper内部的WrapperValve创建FilterChain实例,调用指定的Servlet实例处理请求。

    7. 返回

    1.1 EngineValve

    得到EnginePipeline

    在这里插入图片描述

    得到管道的阀门, 默认为basicStandardEngineValve

    StandardEngineValve.invoke()

    在这里插入图片描述

    1.2 HostValve

    ErrorReportValve -> StandardHostValve

    ErrorReportValve .invoke()

    在这里插入图片描述

    StandardHostValve.invoke()

    在这里插入图片描述

    1.3 ContextValve

    AuthenticatorBase -> NonLoginAuthenticator -> StandardContextValue

    StandardContextValve.invoke()

    在这里插入图片描述

    在这个方法中解释了为什么 /WEB-INF/下的资源不可以直接请求的原因

            MessageBytes requestPathMB = request.getRequestPathMB();
            if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
                    || (requestPathMB.equalsIgnoreCase("/META-INF"))
                    || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
                    || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND); //解释了 /WEB-INF/下的资源为什么不能直接请求
                return;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1.4 WrapperValve

    Wrapper封装了Servlet的信息

    StandardWrapperValve.invoke()

    1. 创建了Servlet对象
    2. 初始化了Servlet对象
    3. 准备FIlter链, 并执行Filter链
    4. 最后执行了Servlet.service()

    在这里插入图片描述

    创建并初始化Servlet

    在这里插入图片描述

    准备了一个FIlterChain

    在这里插入图片描述

    执行FilterChain

    所以Tomcat在请求到达Servlet之前会执行FilterChain

    ApplicationFilterChain.doFilter()

    在这里插入图片描述

    ApplicationFilterChain.internalDoFilter()

    在这里插入图片描述

    最后执行了Servlet.service()

    然后执行了HttpServlet.service()

    @Override
        public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException {
     
            HttpServletRequest  request;
            HttpServletResponse response;
     
            try {
                request = (HttpServletRequest) req;
                response = (HttpServletResponse) res;
            } catch (ClassCastException e) {
                throw new ServletException(lStrings.getString("http.non_http"));
            }
            service(request, response);
        }
    
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
     
            String method = req.getMethod();
     
            if (method.equals(METHOD_GET)) {
                long lastModified = getLastModified(req);
                if (lastModified == -1) {
                    // servlet doesn't support if-modified-since, no reason
                    // to go through further expensive logic
                    doGet(req, resp);
                } else {
                    long ifModifiedSince;
                    try {
                        ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                    } catch (IllegalArgumentException iae) {
                        // Invalid date header - proceed as if none was set
                        ifModifiedSince = -1;
                    }
                    if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                        // If the servlet mod time is later, call doGet()
                        // Round down to the nearest second for a proper compare
                        // A ifModifiedSince of -1 will always be less
                        maybeSetLastModified(resp, lastModified);
                        doGet(req, resp);
                    } else {
                        resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                    }
                }
     
            } else if (method.equals(METHOD_HEAD)) {
                long lastModified = getLastModified(req);
                maybeSetLastModified(resp, lastModified);
                doHead(req, resp);
     
            } else if (method.equals(METHOD_POST)) {
                doPost(req, resp);
     
            } else if (method.equals(METHOD_PUT)) {
                doPut(req, resp);
     
            } else if (method.equals(METHOD_DELETE)) {
                doDelete(req, resp);
     
            } else if (method.equals(METHOD_OPTIONS)) {
                doOptions(req,resp);
     
            } else if (method.equals(METHOD_TRACE)) {
                doTrace(req,resp);
     
            } else {
                //
                // Note that this means NO servlet supports whatever
                // method was requested, anywhere on this server.
                //
     
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object[] errArgs = new Object[1];
                errArgs[0] = method;
                errMsg = MessageFormat.format(errMsg, errArgs);
     
                resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    在转换完Response和Request后,service会调用重载的service方法,此时则开始正式执行Get,Post等等.

    2.Valve

    为阀门, 为一个责任链模式

    在这里插入图片描述
    通过getNext()获取到下一个阀门

    在这里插入图片描述
    实现类:

    • StandardWrapperValve
    • StandardContextValve
    • StandardHostValve
    • StandardEngineValve
  • 相关阅读:
    Python模板注入(SSTI)
    curlpp(curl C++) http错误码和重定向后的url获取
    基于Python+Html的番剧更新表及番剧详情数据库
    每日一题:241. 为运算表达式设计优先级
    图像修复论文阅读笔记-----Globally and Locally Consistent Image Completion
    哪款TWS耳机音质比较好?音质最好的TWS耳机推荐
    【论文阅读】MPViT : Multi-Path Vision Transformer for Dense Prediction
    笔记_前端基础试题:HTML+CSS
    糖友吃什么有助于控制血糖
    Java代码优化的30个小技巧
  • 原文地址:https://blog.csdn.net/qq_43141726/article/details/125983245