中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java源碼分析SpringMVC執行流程

發布時間:2023-04-20 16:13:04 來源:億速云 閱讀:100 作者:iii 欄目:開發技術

本篇內容介紹了“Java源碼分析SpringMVC執行流程”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

先看流程

先看一下SpringMVC執行流程再看源碼,有助理解:

  1. ?戶發送請求?前端控制器DispatcherServlet。

  2. DispatcherServlet 收到請求調? HandlerMapping 處理器映射器。

  3. 處理器映射器找到具體的處理器(可以根據xml配置、注解進?查找),?成處理器及處理器攔截器(如果有則?成)?并返回給DispatcherServlet。

  4. DispatcherServlet調?HandlerAdapter處理器適配器。

  5. HandlerAdapter經過適配調?具體的處理器(Controller,也叫后端控制器)

  6. Controller執?完成返回ModelAndView。

  7. HandlerAdapter 將 Controller 執?結果 ModelAndView 返回給DispatcherServlet。

  8. DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。

  9. ViewReslover解析后返回具體View。

  10. DispatcherServlet根據View進?渲染視圖(即將模型數據填充?視圖中)。

  11. DispatcherServlet 響應?戶。

Java源碼分析SpringMVC執行流程

再看源碼

我們都知道當從用戶發起請求到后端是,首先走的就是DispatcherServlet,接著就會調用doService()方法執行業務邏輯,doService()方法也只是一個中轉站,實際執行邏輯的是doDispatch()方法,且看源碼:

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);
    // 省略部分源碼
    try {
        // 執行實際邏輯
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
        ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
    }
}

doDispatch 方法:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

        try {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 為當前請求獲取映射處理器
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 獲取映射處理器適配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 實際調用的Handler
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        //處理轉發結果
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

下面來看一下其中幾個重要的方法:

1.getHandler(HttpServletRequest request)方法:該方法是處理當前請求找到合適的HandlerMapping,并返回一個HandlerExecutionChainHandlerExecutionChainHandlerExecutionChain包含了具體的處理器(handler)和攔截器列表。

HandlerMapping 默認的實現有org.springframework.web.servlet.handler.BeanNameUrlHandlerMappingorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

2.getHandlerAdapter(Object handler) 根據HandlerExecutionChain中的handler來獲取處理器適配器(HandlerAdapter),

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
            "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

HandlerAdapter有兩個默認實現類,分別是 org.springframework.web.servlet.mvc.HttpRequestHandlerAdapterorg.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,前者用于沒有使用模板引擎的請求,后者用于使用了模板引擎的接口。

實際處理請求的是HandlerAdapter的handle方法,如果是沒有使用例如JSP等的模板引擎,handle方法就會返回null,如果使用了模板引擎就會返回一個ModelAndView對象。

ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

handle方法最終調用的是Controller接口的 handleRequest(HttpServletRequest request, HttpServletResponse response) 方法來處理請求。

以SimpleControllerHandlerAdapter#handle方法源碼為例:

@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
    return ((Controller) handler).handleRequest(request, response);
}

3.processDispatchResult方法用于處理轉發結果,該結果要么是一個ModelAndView,要么拋異常。

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

    boolean errorView = false;

    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            //處理異常
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // Did the handler return a view to render?
    if (mv != null && !mv.wasCleared()) {
        //加載視圖
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    } else {
        if (logger.isTraceEnabled()) {
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        // Concurrent handling started during a forward
        return;
    }

    if (mappedHandler != null) {
        // Exception (if any) is already handled..
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

processDispatchResult方法中在正常情況下會調用render方法。

4.render方法用來通過名稱呈現視圖,它也是請求處理的最后一步。

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Determine locale for request and apply it to the response.
    Locale locale =
            (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
    response.setLocale(locale);

    View view;
    String viewName = mv.getViewName();
    if (viewName != null) {
        // 通過視圖名稱獲取視圖
        view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
        if (view == null) {
            throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                    "' in servlet with name '" + getServletName() + "'");
        }
    }
    else {
        // No need to lookup: the ModelAndView object contains the actual View object.
        view = mv.getView();
        if (view == null) {
            throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                    "View object in servlet with name '" + getServletName() + "'");
        }
    }

    // Delegate to the View object for rendering.
    if (logger.isTraceEnabled()) {
        logger.trace("Rendering view [" + view + "] ");
    }
    try {
        if (mv.getStatus() != null) {
            response.setStatus(mv.getStatus().value());
        }
        //渲染視圖
        view.render(mv.getModelInternal(), request, response);
    }
    catch (Exception ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Error rendering view [" + view + "]", ex);
        }
        throw ex;
    }
}

DispatcherServlet的render方法是對視圖View的封裝,最后調用的還是Viewrender方法。

resolveViewName方法用于解析視圖名稱,它會通過視圖解析器ViewResolverresolveViewName方法解析視圖并返回一個視圖View,然后再通過Viewrender方法渲染視圖,至于是怎么渲染視圖的這里就不介紹了,感興趣的可以自行查看源碼。

protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {
    if (this.viewResolvers != null) {
        for (ViewResolver viewResolver : this.viewResolvers) {
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                return view;
            }
        }
    }
    return null;
}

“Java源碼分析SpringMVC執行流程”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

武义县| 马尔康县| 赤水市| 静安区| 依安县| 金华市| 青河县| 扶绥县| 通海县| 固始县| 大名县| 乐清市| 呈贡县| 容城县| 贡嘎县| 正镶白旗| 万宁市| 新河县| 咸丰县| 土默特右旗| 乐亭县| 手游| 突泉县| 普兰店市| 乐清市| 上犹县| 福安市| 新兴县| 安义县| 五莲县| 彰武县| 屏东县| 华阴市| 蕉岭县| 元阳县| 商城县| 顺昌县| 常宁市| 常熟市| 丰城市| 香河县|