本文節選自《Spring 5核心原理》
1 什么是Spring MVC
Spring MVC 是 Spring 提供的一個基于 MVC 設計模式的輕量級 Web 開發框架,本質上相當于 Servlet,Spring MVC 角色劃分清晰,分工明細,由于 Spring MVC 本身就是 Spring 框架的一部分,可以說和 Spring 框架是無縫集成,性能方面具有先天的優越性,是當今業界最主流的 Web 開發框架,最熱門的開發技能,
首先從一個由Spring提供的DispatcherServlet開始,重寫了Serlvet的init()方法、service()方法和destroy()方法,SpringMVC九大組件在DispatcherServlet的init()方法中初始化,在service()方法中執行,下面,我們先來看Spring MVC九大組件的初始化,
2 SpringMVC九大組件名稱解釋
Spring MVC九大組件在DispatcherServlet的init()方法中初始化,下面我詳細介紹一下Spring MVC九大組件的名稱和作用,
| 序號 | 組件名 | 解釋 |
|---|---|---|
| 1 | MultipartResolver | 用于處理多檔案上傳請求, |
| 2 | LocaleResolver | 用于從請求中決議出 Locale,是i18n的基礎, |
| 3 | ThemeResolver | 用來決議樣式、圖片及它們所形成的顯示效果的集合, |
| 4 | HandlerMapping | 保存Url和邏輯處理的映射關系, |
| 5 | HandlerAdapter | 動態引數配接器,讓固定的Servlet處理方法呼叫Handler來進行處理 |
| 6 | HandlerExceptionResolver | 用來處理Handler產生的例外情況的組件, |
| 7 | RequestToViewNameTranslator | 從請求中獲取ViewName |
| 8 | ViewResolvers | 主要作用是將String型別的視圖名和Locale決議為View型別的視圖 |
| 9 | FlashMapManager | 用于重定向時的引數傳遞, |
具體詳細介紹如下:
2.1 MultipartResolver
MultipartResolver是一個大家很熟悉的組件,用于處理上傳請求,通過將普通的請求包裝成MultipartHttpServletRequest來實作,MultipartHttpServletRequest可以通過getFile()方法直接獲得檔案,如果上傳多個檔案,還可以呼叫getFileMap()方法得到 Map< FileName, File> 這樣的結構,MultipartResolver的作用就是封裝普通的請求,使其擁有檔案上傳的功能,
2.2 LocaleResolver
ViewResolver組件的resolveViewName()方法需要兩個引數,一個是視圖名,另一個就是Locale,引數Locale是從哪來的呢?這就是LocaleResolver組件要做的事,LocaleResolver用于從請求中決議出 Locale,比如在中國Locale當然就是zh-CN,用來表示一個區域,這個組件也是i18n的基礎,
2.3 ThemeResolver
從名字便可看出,ThemeResolver組件是用來決議主題的,主題就是樣式、圖片及它們所形成的顯示效果的集合,Spring MVC中一套主題對應一個properties檔案,里面存放著與當前主題相關的所有資源,如圖片、CSS樣式等,創建主題非常簡單,只需準備好資源,然后新建一個“主題名.properties”并將資源設定進去,放在classpath下,之后便可以在頁面中使用了,Spring MVC中與主題有關的類有ThemeResolver、ThemeSource和Theme,ThemeResolver負責從請求中決議出主題名,ThemeSource則根據主題名找到具體的主題,其抽象也就是Theme,可以通過Theme來獲取主題和具體的資源,
2.4 HandlerMapping
HandlerMapping是用來查找Handler的,也就是處理器,具體的表現形式可以是類,也可以是方法,比如,標注了@RequestMapping的每個方法都可以看成一個Handler,Handler負責實際的請求處理,在請求到達后,HandlerMapping的作用便是找到請求相應的處理器Handler和Interceptor,
2.5 HandlerAdapter
從名字上看,HandlerAdapter是一個配接器,因為Spring MVC中Handler可以是任意形式的,只要能夠處理請求便可,但是把請求交給Servlet的時候,由于Servlet的方法結構都是doService(HttpServletRequest req, HttpServletResponse resp)形式的,要讓固定的Servlet處理方法呼叫Handler來進行處理,這一步作業便是HandlerAdapter要做的事,
2.6 HandlerExceptionResolver
從組件的名字上看,HandlerExceptionResolver是用來處理Handler產生的例外情況的組件,具體來說,此組件的作用是根據例外設定ModelAndView,之后交給渲染方法進行渲染,渲染方法會將ModelAndView渲染成頁面,不過要注意,HandlerExceptionResolver只用于決議對請求做處理階段產生的例外,渲染階段的例外不歸它管,這也是Spring MVC 組件設計的一大原則—分工明確、互不干涉,
2.7 RequestToViewNameTranslator
RequestToViewNameTranslator組件的作用是從請求中獲取ViewName,因為ViewResolver根據ViewName查找View,但有的Handler處理完成之后,沒有設定View,也沒有設定ViewName,便要通過這個組件來從請求中查找ViewName,
2.8 ViewResolver
ViewResolver即視圖決議器,相信大家對這個組件應該很熟悉了,通常在Spring MVC的組態檔中,都會配上一個實作類來進行視圖決議,這個組件的主要作用是將String型別的視圖名和Locale決議為View型別的視圖,只有一個resolveViewName()方法,從方法的定義可以看出,Controller層回傳的String型別的視圖名viewName最侄訓在這里被決議成為View,View是用來渲染頁面的,也就是說,它會將程式回傳的引數和資料填入模板中,生成HTML檔案,ViewResolver在這個程序中主要做兩件大事:ViewResolver會找到渲染所用的模板(第一件大事)和所用的技術(第二件大事,其實也就是找到視圖的型別,如JSP)并填入引數,默認情況下,Spring MVC會為我們自動配置一個InternalResourceViewResolver,是針對JSP型別視圖的,
2.9 FlashMapManager
說到FlashMapManager組件,得先說一下FlashMap,
FlashMap用于重定向時的引數傳遞,比如在處理用戶訂單時,為了避免重復提交,可以處理完post請求后重定向到一個get請求,這個get請求可以用來顯示訂單詳情之類的資訊,這樣做雖然可以規避用戶重新提交訂單的問題,但是在這個頁面上要顯示訂單的資訊,這些資料從哪里獲取呢?因為重定向是沒有傳遞引數這一功能的,如果不想把引數寫進URL(其實也不推薦這么做,除了URL有長度限制,把引數都直接暴露也不安全),那么就可以通過FlashMap來傳遞,只需要在重定向之前將要傳遞的資料寫入請求(可以通過ServletRequestAttributes.getRequest()方法獲得)的屬性OUTPUT_FLASH_MAP_ATTRIBUTE中,這樣在重定向之后的Handler中Spring就會自動將其設定到Model中,在顯示訂單資訊的頁面上就可以直接從Model中獲得資料,
FlashMapManager就是用來管理FlashMap的,
3 Spring MVC關鍵組件的執行流程
Spring MVC九大組件的執行在DispatcherServlet的service()方法中完成,在這里,我重點介紹幾個關鍵組件HandlerMapping、HandlerAdapter、ViewResolver在service()方法中的執行流程,具體呼叫分為以下幾個步驟:
1、HandlerMapping回到呼叫HandlerAdapter
2、HandlerAdapter會回傳ModelAndView
3、ModelAndView根據用戶傳入引數得到ViewResolvers
4、ViewResolvers會將用戶傳入的引數封裝為View,交給引擎進行渲染,
下面給大家分享一張Spring MVC關鍵組件的執行流程圖,以幫助大家更好地理解:

注意:上圖中有大家最熟悉的兩個類:ModelAndView和View類并不屬于Spring MVC九大組件之列,
4 Spring MVC優化建議
前面我們已經對Spring MVC的作業原理和原始碼進行了分析,在這個程序中有幾個優化點,
1. Controller如果能保持單例模式,盡量使用單例模式
這樣可以減小創建物件和回收物件的開銷,也就是說,如果Controller的類變數和實體變數可以以方法形參宣告就盡量以方法形參宣告,不要以類變數和實體變數宣告,這樣可以避免執行緒安全問題,
2. 處理請求的方法中的形參務必加上@RequestParam注解
這樣可以避免Spring MVC使用asm框架讀取.class檔案獲取方法引數名,即便Spring MVC對讀取出的方法引數名進行了快取,如果能不讀取.class檔案當然更好,
3. 快取URL
在閱讀原始碼的程序中,我們發現Spring MVC并沒有對處理URL的方法進行快取,也就是說,每次都要根據請求URL去匹配Controller中的方法的URL,如果把URL和方法的關系快取起來,會不會帶來性能上的提升呢?不幸的是,負責決議URL和方法對應關系的ServletHandlerMethodResolver是一個私有的內部類,不能直接通過繼承該類增強代碼,必須在代碼后重新編譯,當然,如果將URL快取起來,必須考慮快取的執行緒安全問題,

本文為“Tom彈架構”原創,轉載請注明出處,技術在于分享,我分享我快樂!
如果本文對您有幫助,歡迎關注和點贊;如果您有任何建議也可留言評論或私信,您的支持是我堅持創作的動力,
原創不易,堅持很酷,都看到這里了,小伙伴記得點贊、收藏、在看,一鍵三連加關注!如果你覺得內容太干,可以分享轉發給朋友滋潤滋潤!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/390240.html
標籤:其他
