最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java從源碼角度解析SpringMVC執(zhí)行流程

 更新時(shí)間:2023年04月20日 11:13:04   作者:索碼理  
這篇文章主要介紹了Java從源碼角度解析SpringMVC執(zhí)行流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

SpringMVC執(zhí)行流程在面試中經(jīng)常會(huì)被問(wèn)到,本篇文章通過(guò)源碼的方式簡(jiǎn)單的了解一下SpringMVC執(zhí)行流程。

先看流程

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

  1. ?戶發(fā)送請(qǐng)求?前端控制器DispatcherServlet。
  2. DispatcherServlet 收到請(qǐng)求調(diào)? HandlerMapping 處理器映射器。
  3. 處理器映射器找到具體的處理器(可以根據(jù)xml配置、注解進(jìn)?查找),?成處理器及處理器攔截器(如果有則?成)?并返回給DispatcherServlet。
  4. DispatcherServlet調(diào)?HandlerAdapter處理器適配器。
  5. HandlerAdapter經(jīng)過(guò)適配調(diào)?具體的處理器(Controller,也叫后端控制器)
  6. Controller執(zhí)?完成返回ModelAndView。
  7. HandlerAdapter 將 Controller 執(zhí)?結(jié)果 ModelAndView 返回給DispatcherServlet。
  8. DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。
  9. ViewReslover解析后返回具體View。
  10. DispatcherServlet根據(jù)View進(jìn)?渲染視圖(即將模型數(shù)據(jù)填充?視圖中)。
  11. DispatcherServlet 響應(yīng)?戶。

SpringMVC執(zhí)行流程

再看源碼

我們都知道當(dāng)從用戶發(fā)起請(qǐng)求到后端是,首先走的就是DispatcherServlet,接著就會(huì)調(diào)用doService()方法執(zhí)行業(yè)務(wù)邏輯,doService()方法也只是一個(gè)中轉(zhuǎn)站,實(shí)際執(zhí)行邏輯的是doDispatch()方法,且看源碼:

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);
    // 省略部分源碼
    try {
        // 執(zhí)行實(shí)際邏輯
        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);

            // 為當(dāng)前請(qǐng)求獲取映射處理器
            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;
            }

            // 實(shí)際調(diào)用的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);
        }
        //處理轉(zhuǎn)發(fā)結(jié)果
        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);
            }
        }
    }
}

下面來(lái)看一下其中幾個(gè)重要的方法:

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

HandlerMapping 默認(rèn)的實(shí)現(xiàn)有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) 根據(jù)HandlerExecutionChain中的handler來(lái)獲取處理器適配器(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有兩個(gè)默認(rèn)實(shí)現(xiàn)類,分別是 org.springframework.web.servlet.mvc.HttpRequestHandlerAdapterorg.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,前者用于沒(méi)有使用模板引擎的請(qǐng)求,后者用于使用了模板引擎的接口。

實(shí)際處理請(qǐng)求的是HandlerAdapter的handle方法,如果是沒(méi)有使用例如JSP等的模板引擎,handle方法就會(huì)返回null,如果使用了模板引擎就會(huì)返回一個(gè)ModelAndView對(duì)象。

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

handle方法最終調(diào)用的是Controller接口的 handleRequest(HttpServletRequest request, HttpServletResponse response) 方法來(lái)處理請(qǐng)求。

以SimpleControllerHandlerAdapter#handle方法源碼為例:

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

3.processDispatchResult方法用于處理轉(zhuǎn)發(fā)結(jié)果,該結(jié)果要么是一個(gè)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方法中在正常情況下會(huì)調(diào)用render方法。

4.render方法用來(lái)通過(guò)名稱呈現(xiàn)視圖,它也是請(qǐng)求處理的最后一步。

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) {
        // 通過(guò)視圖名稱獲取視圖
        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方法是對(duì)視圖View的封裝,最后調(diào)用的還是Viewrender方法。

resolveViewName方法用于解析視圖名稱,它會(huì)通過(guò)視圖解析器ViewResolverresolveViewName方法解析視圖并返回一個(gè)視圖View,然后再通過(guò)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;
}

到此這篇關(guān)于Java從源碼角度解析SpringMVC執(zhí)行流程的文章就介紹到這了,更多相關(guān)JavaSpringMVC執(zhí)行流程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java調(diào)用構(gòu)造函數(shù)和方法及使用詳解

    Java調(diào)用構(gòu)造函數(shù)和方法及使用詳解

    在Java編程中,構(gòu)造函數(shù)用于初始化新創(chuàng)建的對(duì)象,而方法則用于執(zhí)行對(duì)象的行為,構(gòu)造函數(shù)在使用new關(guān)鍵字創(chuàng)建類實(shí)例時(shí)自動(dòng)調(diào)用,沒(méi)有返回類型,并且名稱與類名相同,本文通過(guò)示例詳細(xì)介紹了如何在Java中使用構(gòu)造函數(shù)和方法,感興趣的朋友一起看看吧
    2024-10-10
  • mybatis中字段名與關(guān)鍵字相同問(wèn)題

    mybatis中字段名與關(guān)鍵字相同問(wèn)題

    這篇文章主要介紹了mybatis中字段名與關(guān)鍵字相同問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java 實(shí)戰(zhàn)項(xiàng)目錘煉之網(wǎng)上花店商城的實(shí)現(xiàn)流程

    Java 實(shí)戰(zhàn)項(xiàng)目錘煉之網(wǎng)上花店商城的實(shí)現(xiàn)流程

    讀萬(wàn)卷書(shū)不如行萬(wàn)里路,只學(xué)書(shū)上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+jsp+servlet+mysql+ajax實(shí)現(xiàn)一個(gè)網(wǎng)上花店商城系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • logback-spring.xml的內(nèi)容格式詳解

    logback-spring.xml的內(nèi)容格式詳解

    這篇文章主要介紹了logback-spring.xml的內(nèi)容格式詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的的朋友參考下吧
    2023-11-11
  • Java中處理金額計(jì)算之使用Long還是BigDecimal詳解

    Java中處理金額計(jì)算之使用Long還是BigDecimal詳解

    在Java后端開(kāi)發(fā)中處理與錢有關(guān)的業(yè)務(wù)時(shí),確保金額計(jì)算的準(zhǔn)確性和避免錯(cuò)誤非常重要,這篇文章主要給大家介紹了關(guān)于Java中處理金額計(jì)算之使用Long還是BigDecimal的相關(guān)資料,需要的朋友可以參考下
    2024-07-07
  • 基于Properties實(shí)現(xiàn)配置數(shù)據(jù)庫(kù)驅(qū)動(dòng)

    基于Properties實(shí)現(xiàn)配置數(shù)據(jù)庫(kù)驅(qū)動(dòng)

    這篇文章主要介紹了基于Properties實(shí)現(xiàn)配置數(shù)據(jù)庫(kù)驅(qū)動(dòng),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Java多線程系列之JDK并發(fā)包舉例詳解

    Java多線程系列之JDK并發(fā)包舉例詳解

    Java并發(fā)包提供了許多用于多線程編程的類和接口,這篇文章主要給大家介紹了關(guān)于Java多線程系列之JDK并發(fā)包的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-03-03
  • Springboot實(shí)現(xiàn)前后端分離excel下載

    Springboot實(shí)現(xiàn)前后端分離excel下載

    這篇文章主要介紹了Springboot實(shí)現(xiàn)前后端分離excel下載,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java線程池FutureTask實(shí)現(xiàn)原理詳解

    Java線程池FutureTask實(shí)現(xiàn)原理詳解

    這篇文章主要介紹了Java線程池FutureTask實(shí)現(xiàn)原理詳解,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • Springboot2.x 使用 Log4j2 異步打印日志的實(shí)現(xiàn)

    Springboot2.x 使用 Log4j2 異步打印日志的實(shí)現(xiàn)

    這篇文章主要介紹了Springboot2.x 使用 Log4j2 異步打印日志的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12

最新評(píng)論

城步| 贞丰县| 太仓市| 汉阴县| 长武县| 长岭县| 精河县| 建瓯市| 嘉义县| 五峰| 克拉玛依市| 库尔勒市| 临沂市| 汉阴县| 双峰县| 辉南县| 天水市| 湾仔区| 开阳县| 浠水县| 运城市| 大方县| 乌兰察布市| 武穴市| 岳阳市| 海安县| 弥勒县| 长海县| 邓州市| 铁力市| 新兴县| 来安县| 沙田区| 垣曲县| 镇江市| 栾城县| 会东县| 泾源县| 古蔺县| 玉田县| 福清市|