SpringMVC源码阅读-一个请求主体处理流程(四)

流程图

摘自:https://www.tianxiaobo.com/2018/06/29/Spring-MVC-原理探秘-一个请求的旅行过程/

继承关系图

 1.GenericServlet 只是一个抽象类提供一些基础的模板 具体实现由以下子类实现

2.HTTPServlet提供了对service的实现

HttppServlet

service

javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)

 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
            //转为HttpServletRequest
            HttpServletRequest request = (HttpServletRequest)req;
            //转为HttpServletResponse
            HttpServletResponse response = (HttpServletResponse)res;
            //<1>交给当前类的service方法处理 这里不是调用当前类的 而是调用子类FrameworkServlet的 重写了
            this.service(request, response);
        } else {
            throw new ServletException("non-HTTP request or response");
        }
    }

<2>service

javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)

/**
     * 根据请求方式路由到对应的方法处理
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求协议头的请求方式 如:Request Method: GET
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            //-1则表示缓存绝对更新了  默认子类没有实现 直接返回的-1
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                //<3>根据协议版本 返回400 405空实现 由子类实现
                this.doGet(req, resp);
            } else {
                /**
                 *  <2>如果上一次请求客户端Last-Modified 如:Last-Modified: Thu, 20 Feb 2014 09:02:52 GMT
                 *  一般静态文件会默认带上
                 *  浏览器会将数据缓存本地
                 *  后续浏览器都会带上 每次跟服务器数据更新时间来做比较 如果没更新返回304 空响应
                 *  浏览器直接使用过本地数据
                 */
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                //比较缓存是否过期
                if (ifModifiedSince < lastModified) {
                    this.maybeSetLastModified(resp, lastModified);
                    //<3>根据协议版本 返回400 405空实现 由子类实现
                    this.doGet(req, resp);
                } else {
                    //返回304
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

3.路由的方法都在HettpServlet都是返回405或者400的空实现 由子类实现

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

FrameworkServlet

<1>service

org.springframework.web.servlet.FrameworkServlet#service

 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //如果请求方式是PATCH 则直接调用
        if (HttpMethod.PATCH.matches(request.getMethod())) {
            this.processRequest(request, response);
        } else {
            /**
             * 否则调用父类的路由方法 最终也是调用processRequest
             * <2>作用是是 比如父类的304缓存策略 以及路由的不同方法 处理方式 有所差异 如 option处理方式
             */
            super.service(request, response);
        }

    }

processRequest

org.springframework.web.servlet.FrameworkServlet#service

->

org.springframework.web.servlet.FrameworkServlet#processRequest

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;
        /**
         * <3>获取当前线程 第一次国际化上下文 从里面会从2个ThreadLocal获取
         */
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        //构建单签线程当本次请求的国际化上下文
        LocaleContext localeContext = this.buildLocaleContext(request);
        //<3>获取当前线程第一次请求的RequestAttribute 里面会从2个ThreadLocal获取
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        //<4>构建当前线程的RequestAttribute
        ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
        /**
         *会从requsetAttribute里面获取获取不到初始化一个再set进去 key=WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE
         * 表示我们后去都可以根据reqeust.getAttribute(WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE)获取
         * 用于给管理异步请求
         */
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
        /**
         * <5>这里面会存入根据当前对象成语变量区分翻到哪个线程缓存里面threadContextInheritable 默认为false
         * 我们可以利用前面的BeanWapper进行修改
         * 表示我们后续都可以根据LocaleContextHolder和RequestContextHolder获取
         */
        this.initContextHolders(request, localeContext, requestAttributes);

        try {
            //<6>
            this.doService(request, response);
        } catch (ServletException var17) {
            failureCause = var17;
            throw var17;
        } catch (IOException var18) {
            failureCause = var18;
            throw var18;
        } catch (Throwable var19) {
            failureCause = var19;
            throw new NestedServletException("Request processing failed", var19);
        } finally {
            /**
             *  <7>默认previousLocaleContext previousAttributes 是null
             *  这里主要是还原 重置将第一次的set会线程池下次<3>处又可以继续获取到
             */
            this.resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                requestAttributes.requestCompleted();
            }

            if (this.logger.isDebugEnabled()) {
                if (failureCause != null) {
                    this.logger.debug("Could not complete request", (Throwable)failureCause);
                } else if (asyncManager.isConcurrentHandlingStarted()) {
                    this.logger.debug("Leaving response open for concurrent processing");
                } else {
                    this.logger.debug("Successfully completed request");
                }
            }
            //spring事件机制 发布ServletRequestHandlerEvent消息,这个请求是否执行成功都会发布消息的
            this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
        }

    }

猜你喜欢

转载自www.cnblogs.com/LQBlog/p/12202596.html
今日推荐