Spring 框架中Http請求處理流程


Spring Web http request請求流程:

首先介紹這邊你需要知道的繼承體系,DispacherServlet繼承自FrameworkServlet,FrameworkServlet繼承自HttpServletBean,HttpServletBean繼承自HttpServlet,HttpServlet繼承自GenericServlet,GenericServlet實現Servlet、ServletConfig接口,我們的流程從請求進入到GenericServlet的service方法開始說起。
  • 攔截器是在DispacherServlet的doDispatch方法中執行的,(url攔截器和用戶自定義的其他業務攔截器)

流程總覽:

容器監聽端口,接收到請求后調用Servlet的service方法,

在service方法中判斷用戶使用的是get還是post請求,決定后續調用對應的doGet/doPost方法,

在doGet/doPost方法中執行processRequest方法,

processRequest方法執行請求上下文的初始化過程,

然后調用doService()方法,

由該doService方法執行doDispatch方法,

最后由doDispatch方法去獲取請求的mappedHandler和HandlerAdapter,處理完用戶請求之后通過新建一個ServletWebRequest來渲染返回數據

首先調用GenericServlet的service()方法,源碼如下:
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
事實上GenericServlet的service()方法是一個抽象方法,而HttpServlet繼承了GenericServlet,所以此處實際調用了HttpServlet的service方法,HttpServlet的service方法源碼如下:

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
    HttpServletRequest request = (HttpServletRequest)req;
    HttpServletResponse response = (HttpServletResponse)res;
    this.service(request, response);
     } else {
         throw new ServletException("non-HTTP request or response");
    }
 }
首先判斷ServletRequest、ServletResponse是否是標准的HttpServletRequest、HttpServletResponse,如果不是則拋出ServletException異常,否則繼續調用實現類的service()方法
對源碼做debug我們知道,this.service(request, response);執行到spring FrameworkServlet的service方法。
在spring框架中,FrameworkServlet繼承自HttpServletBean,HttpServletBean是一個抽象類,HttpServletBean繼承自HttpServlet。
所以HttpServlet的service方法中調用的this.service(request, response);其實是執行的是FrameworkServlet中的service方法。繼續看源碼:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
        super.service(request, response);
    } else {
        this.processRequest(request, response);
    }

}
我們的HttpMethod 應該是POST或者GET方法,所以執行super.service(request, response);回到HttpServlet的service(HttpServletRequest req, HttpServletResponse resp)方法:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String method = req.getMethod();
    long lastModified;
    if (method.equals("GET")) {
        lastModified = this.getLastModified(req);
        if (lastModified == -1L) {
            this.doGet(req, resp);
        } else {
            long ifModifiedSince = req.getDateHeader("If-Modified-Since");
            if (ifModifiedSince < lastModified) {
                this.maybeSetLastModified(resp, lastModified);
                this.doGet(req, resp);
            } else {
                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);
    }
}
我們一GET請求為例,直接看this.doGet(req, resp);回到FrameworkServlet的doGet方法:
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.processRequest(request, response);
}
執行processRequest方法:
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;
    //
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = this.buildLocaleContext(request);//此處調用其實現類的buildLocaleContext方法,spring中即DispatcherServlet,來創建localeContext 對象
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    //注冊攔截器registerCallableInterceptor
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
    //初始化應用context
    this.initContextHolders(request, localeContext, requestAttributes);

    try {
        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 {
        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");
            }
        }

        this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
    }

}
可以看到,在FrameworkServlet的processRequest方法中執行了一系列的初始化操作,然后調用this.doService(request, response);也就是調用DispatcherServlet的doService方法
來看DispatcherServlet的doService方法的源碼:
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //省略掉一些request屬性的代碼
    try {
        this.doDispatch(request, response);
    } finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
            this.restoreAttributesAfterInclude(request, attributesSnapshot);
        }
    }
}
該方法中主要完成一些request的屬性設置,然后this.doDispatch(request, response);源碼如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        try {
            ModelAndView mv = null;
            Object dispatchException = null;

            try {
                //處理multipart 請求
                processedRequest = this.checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                //從容器中獲取mappedHandler 
                mappedHandler = this.getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    this.noHandlerFound(processedRequest, response);
                    return;
                }
                 // 從容器中獲取適配器HandlerAdapter 。這個過程中,會調用MappedInterceptor的matches方法,以此來判斷次url是否在攔截范圍內
                HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                //處理get請求
                if (isGet || "HEAD".equals(method)) {
                    //lastModified最后修改時間 此處返回-1
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    // 檢查請求是否使用緩存
                    if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                //執行攔截器中的preHandle攔截方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                //執行用戶controller中對應的業務
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                //渲染默認的mv
                this.applyDefaultViewName(processedRequest, mv);
                //執行PostHandle攔截方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var20) {
                dispatchException = var20;
            } catch (Throwable var21) {
                dispatchException = new NestedServletException("Handler dispatch failed", var21);
            }
            //渲染返回值
            this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
        } catch (Exception var22) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
        } catch (Throwable var23) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
        }

    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else if (multipartRequestParsed) {
            this.cleanupMultipart(processedRequest);
        }

    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM