SpringMVC運行原理

来源:https://www.cnblogs.com/arebirth/archive/2019/09/14/springmvcexecutereal.html
-Advertisement-
Play Games

按照上邊的執行流程圖,我們可以看出一個SpringMVC整體的一個執行輪廓,下麵我們具體來分析下 首先伺服器接收到一個請求,匹配並調用了我們的前端控制器(DispatcherServlet)也叫中央處理器的請求路徑,在web.xml文件中配置,我們來看下配置文件 因為DispatcherServle ...


 

 

 


按照上邊的執行流程圖,我們可以看出一個SpringMVC整體的一個執行輪廓,下麵我們具體來分析下

 

首先伺服器接收到一個請求,匹配並調用了我們的前端控制器(DispatcherServlet)也叫中央處理器的請求路徑,在web.xml文件中配置,我們來看下配置文件

<servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
  <!-- / 代表匹配所有除了jsp文件的請求 --> <url-pattern>/</url-pattern> </servlet-mapping>

因為DispatcherServlet實際上是間接的繼承了我們的HttpServlet,所以它就相當於一個Servlet,SpringMVC幫我們封裝好的一個Servlet,下麵是繼承體系

 

 

 所以說,當來了一個請求後,WEB容器將把請求交給我們的DispatcherServlet進行處理

DispatcherServlet接收到請求後,會把我們的請求信息交給HandlerMapping處理器映射器進行處理

HandlerMapping根據請求的URL信息去查找匹配的URL的Handler,如果查找成,並返回一個執行鏈,下麵來看下底層執行代碼

 protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Iterator var2 = this.handlerMappings.iterator();

        HandlerExecutionChain handler;
        do {
            if (!var2.hasNext()) {
                return null;
            }

            HandlerMapping hm = (HandlerMapping)var2.next();
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
            }

            handler = hm.getHandler(request);//根據request對象獲取handler,獲取到的話將返回一個對象,沒有的話將返回null  有興趣童鞋自行深入查看
        } while(handler == null);//如果handler為null繼續執行迴圈

        return handler;
    }

如果沒有找到的話將執行以下代碼

 protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (pageNotFoundLogger.isWarnEnabled()) {
            pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) + "] in DispatcherServlet with name '" + this.getServletName() + "'");
        }

        if (this.throwExceptionIfNoHandlerFound) {
            ServletServerHttpRequest sshr = new ServletServerHttpRequest(request);
            throw new NoHandlerFoundException(sshr.getMethod().name(), sshr.getServletRequest().getRequestURI(), sshr.getHeaders());
        } else {
            response.sendError(404);//響應404
        }
    }

找到成功的情況下,DispatcherServlet再次請求 處理器適配器(HandlerAdapter)調用相應的Handler 進行處理返回 ModelAndView 給 DispatcherServlet,底層代碼,粗略看下即可,不是重點

 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 = this.checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                mappedHandler = this.getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    this.noHandlerFound(processedRequest, response);
                    return;
                }

                HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    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;
                    }
                }

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

                mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //在這裡邊調用相應的Handler,並通過這個方法返回ModelAndModel給DispatcherServlet
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }

                this.applyDefaultViewName(request, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var19) {
                dispatchException = var19;
            }

            this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        } catch (Exception var20) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var20);
        } catch (Error var21) {
            this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var21);
        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }

    }

然後DispatcherServlet將ModelAndView請求對應的ViewResolver(視圖解析器)解析視圖,然後返回具體的View,底層實現

 protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
        Iterator var5 = this.viewResolvers.iterator();

        View view;
        do {
            if (!var5.hasNext()) {
                return null;
            }

            ViewResolver viewResolver = (ViewResolver)var5.next();
            view = viewResolver.resolveViewName(viewName, locale);
        } while(view == null);

        return view;
    }

DispatcherServlet對View視圖進行渲染,也就是把模型數據填充到視圖裡邊,底層執行代碼

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Locale locale = this.localeResolver.resolveLocale(request);
        response.setLocale(locale);
        View view;
        if (mv.isReference()) {
            view = this.resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
            }
        } else {
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name '" + this.getServletName() + "'");
            }
        }

        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'");
        }

        try {
            view.render(mv.getModelInternal(), request, response);
        } catch (Exception var7) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'", var7);
            }

            throw var7;
        }
    }

最後DispatcherServlet將視圖傳遞給前臺

 

PS:

Spring MVC核心組件:
    1.DispatcherServlet(中央處理器):將請求轉發給控制器

    2.Controller(控制器):處理請求的控制器

    3.HandlerMapping(映射處理器):負責映射中央處理器轉發給Controller時的映射策略

    4.ModelAndView:伺服器返回數據以及視圖層的封裝類

    5.ViewResolver(視圖解析器):解析具體的視圖

 

當用戶發起請求後,執行DiapacherServlet,如果是JSP直接調用jsp頁面.如果不是JSP,DiapacherServlet調用HandlerMapping判斷請求URL是否合法,如果URL不存在報錯,如果URL存在使用HandlerAdapter調用具體的HandlerMethod,當Handler執行完成後會返回ModelAndView,會被ViewResovler解析,調用具體的物理視圖.
最終響應給客戶端瀏覽器.

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 程式演算法與人生選擇 我用演算法來類比如何做選擇,說白了就是怎麼去計算,但是並沒有講程式員可以發展的方向有哪些。 所以,就算是有這些所謂的方法論,我們可能對自己的發展還是會很糾結和無所事從,尤其是人到了30歲,這種彷徨和迷惑越來越重。雖然我之前也寫過一篇《編程年齡和編程技能》的文章,但是還是有很多做技術 ...
  • 1.為 Python 2 安裝 pip 首先,確保已經安裝了 Python 2。 在 Ubuntu 上,可以使用以下命令進行驗證 如果沒有錯誤並且顯示了 Python 版本的有效輸出,則說明安裝了 Python 2。 所以現在你可以使用這個命令為 Python 2 安裝 pip: 這將安裝 pip ...
  • busuanzi計數腳本 busuanzi官方指引 一、安裝腳本(必選) 要使用不蒜子必須在頁面中引入busuanzi.js,目前最新版如下。 不蒜子可以給任何類型的個人站點使用,如果你是用的hexo,打開themes/你的主題/layout/_partial/footer.ejs添加上述腳本即可, ...
  • 為什麼要抽模板,因為這樣能夠復用代碼,減少代碼量,需要原代碼時就不需要修改,也不需要添加; 如果不同,就只需要單獨修改不一樣的地方就行 : 多挖坑,少代碼,這就是抽模板的精髓,挖坑就是({% block xxx %}需要改變的代碼{% endblock %}) 靜態頁面抽取模板 一、分析靜態頁面 1 ...
  • 一、起因 從《大型網站架構系列》到《架構師入門實踐》,一直想把代碼設計和架構的知識進行總結,但是苦於精力和能力有限,推動起來比較緩慢。也多次收到出版社的邀請,但遲遲沒有動筆。偶爾也會糾結做視頻還是寫文章,考慮到業餘寫作和工作之間的平衡,還是先以文章為主吧。寫出來和大家交流,算是自己的一個知識總結,如 ...
  • MVC模式 在講解Servlet前,先介紹一下MVC模式。 M:model 模型,相當於數據層,用於存放數據,如一個Java中的一個bean類 V:view 視圖,相當於頁面層,用於顯示數據,如一個網頁html,或者是jsp C: controller 控制器,相當於業務層,用於處理數據 我們之前使 ...
  • 一:基礎演算法題5道 1.阿姆斯特朗數 如果一個n位正整數等於其各位數字的n次方之和,則稱該數為阿姆斯特朗數。判斷用戶輸入的數字是否為阿姆斯特朗數。 (1)題目分析:這裡要先得到該數是多少位的,然後再把每一位的數字截取出來,把各位數字的n次方之和和該數一起判斷即可。(2)演算法分析:python中有le ...
  • [TOC] 序言:上一章我們初步介紹了一下Docker的概念,那麼這次我們著手於Docker的使用,瞭解一下常見的Docker的操作命令。此外不管學習什麼東西,我們不但要瞭解縱向的知識體系,最好能加上橫向的擴展,進行類比,Docker的命令風格和Git有著種種相似。好了廢話不多說,我們開始Docke ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...