第2章 Spring MVC整體架構
本章我們學習Spring MVC的各個組件的功能職責、組件之間的接口定義以及各個組件之間的交互和通信,進而從整體架構的層次上理解Spring MVC框架的基本工作原理。
2.1 組件之間的整體交互流程
一個HTTP請求發送到Web容器,Web容器就會封裝一個HTTP請求(HttpServletRequest)對象,這個對象包含所有的HTTP請求信息,例如:HTTP參數以及參數值,HTTP請求頭的各種元數據等。同時,Web容器會創建一個HTTP響應(HttpServletResponse)對象,用以發送HTTP響應內容給客戶端用戶。然后,Web容器傳遞HTTP請求(HttpServletRequest)對象和HTTP響應(HttpServletResponse)對象給Servlet對象的service方法。
實際上,Spring MVC的入口是一個定制化的Servlet,稱為派遣器Servlet(DispatcherServlet)。這個派遣器Servlet得到HTTP請求(HttpServletRequest)對象和HTTP響應(HttpServletResponse)對象后,一個典型的Spring MVC工作流程就開始了。
接下來發生的Spring MVC工作流程如圖2-1所示。
派遣器Servlet首先查找所有注冊的處理器映射器(HandlerMapping)對象,然后,遍歷所有的處理器映射器對象,直到一個處理器映射器對象返回一個非空的處理器執行鏈(HandlerExecutionChain)對象。處理器執行鏈對象包含一個需要處理當前HTTP請求的一個處理器(Handler)對象,如圖2-1的第1步所示。
一個處理器對象被設計成了一個通用的對象類型,這里需要一個處理器適配器(HandlerAdaptor)來派遣這個控制流到一個處理器對象,因為只有支持這種類型的處理器對象的處理器適配器才知道如何去傳遞控制流給這個類型的處理器對象。
拿到了處理器對象以后,派遣器Servlet對象查找所有注冊的處理器適配器對象,然后,遍歷所有的處理器適配器對象查詢是否有一個處理器適配器對象支持這個處理器對象,如圖2-1第2步所示。
如果有這樣的一個處理器適配器對象,則派遣器Servlet對象將控制權轉交給這個派遣器適配器對象,如圖表2-1第3步所示。派遣器適配器對象和真正的處理器對象是成對出現的,所以,這個支持的處理器適配器對象知道如何去使用這個處理器來處理當前請求。
最簡單的一個處理器則是控制器對象(Controller)。處理器適配器對象將傳遞HTTP請求對象和HTTP響應對象給控制器對象,并且期待控制器返回模型和視圖(ModelAndView)對象,如圖2-1第4步所示。這里,模型和視圖對象包含著一組模型數據和視圖邏輯名稱,并且最終返回給派遣器Servlet對象。
派遣器Servlet對象然后查找所有注冊的視圖解析器(ViewResolver)對象,并且遍歷所有的視圖解析器對象,直到一個視圖解析器對象返回一個物理的視圖(View)對象,如圖表2-1第5步所示。
最后,派遣器Servlet把得到的一組模型數據傳遞給得到的物理視圖對象,如圖表2-1第6步所示。然后,視圖對象則會使用表現層技術,把模型數據展現成UI界面,并且通過HTTP響應對象發送給HTTP客戶端。
2.2 組件以及組件的接口
通過上一節對組件之間的整體交互流程的分析,我們看到Spring MVC是由若干組件組成的,這些組件相互獨立又相互協調共同完成Spring MVC的整體工作流程。其中,每個組件都有清晰的接口定義,接口后面都有一個設計良好的類實現體系結構,清晰的抽象出公用的邏輯并且實現在通用的抽象類里,同時提供各種常用的具體實現類,進而實現一個清晰的、高可擴展的、可插拔的MVC體系結構。
這里我們介紹這些典型的組件,組件的功能以及組件所定義的接口。
2.2.1 派遣器Servlet(DispatcherServlet)
派遣器Servlet對象是Spring MVC中最核心的組件之一,也是Spring MVC的總控組件。它是一個實現類而并不是一個接口,從類的繼承角度來看,派遣器Servlet類繼承自FrameworkServlet類,而FrameworkServlet繼承自HttpServlet類,每一層集成完成一定的功能,集成的層次越往上完成的功能約通用,抽象的程度就越高,這樣的類的層級劃分使得派遣器Servlet的類體系結構清晰明了、任務分明、容易擴展,派遣器Servlet類結構如下圖2-2所示。
當應用初始化時,派遣器Servlet對象通過內部的Spring Web應用程序環境,找到相應的Spring MVC的各個組件,如果這些組件沒有顯式配置,Spring MVC將會根據默認加載策略初始化各個模塊的默認實現。
當服務一個HTTP請求時,它通過一套注冊的處理器映射對象找到一個處理器對象,然后,從一套注冊的處理器適配器對象中找到一個支持這個處理器對象的處理器適配器對象,并且通過它把控制流轉發給這個處理器對象,處理器對象結束業務邏輯的調用后把模型數據和邏輯視圖傳回派遣器Servlet對象。
派遣器Servlet對象再通過視圖解析器對象得到真正的視圖對象,把控制權交給視圖對象,同時傳入模型數據,視圖對象會按照一定的視圖層邏輯展現這些數據給HTTP的客戶端用戶。
2.2.2 處理器映射(HandlerMapping)
處理器映射對象是用于映射一個請求對象到一個處理器對象。一個Spring MVC實例可能會包含多個處理器映射對象,按照處理器映射對象所在的順序,第一個返回非空處理器執行鏈對象的處理器映射,會被當作為有效的處理器映射對象。處理器執行鏈對象包含一個處理器對象和一組能夠應用在處理器對象上的攔截器對象(Interceptor).
處理器映射的類結構如下圖2-3所示。
HandlerMapping是一個接口,在這個接口中,通過輸入一個HTTP請求對象給方法getHandler,這個方法就會輸出一個處理器執行鏈對象。進而我們能夠從處理器執行鏈對象獲得一個處理器對象。
2.2.3 處理器適配器(HandlerAdaptor)
處理器適配器對象是用來轉接一個控制流到一個指定類型的處理器對象。一個類型的處理器對象通常會對應一個處理器適配器對象的一個實現。處理器適配器對象能夠判斷自己是否支持某個處理器對象。如果一個處理器適配器對象支持這種類型的處理器,那么這個處理器適配器對象就可以使用這個處理器對象處理當前的這個HTTP請求。
然而,處理器對象是通用的Object類型的一個實例, 這樣做是為了提供高可擴展性,允許Spring MVC可以任意的去集成其他框架的處理器對象,只需要為這個需要支持的處理器對象提供一個定制化的處理器適配器對象即可,就可以在不改變任何上層派遣器Servlet代碼以及下層控制器對象代碼的前提下,實現集成任意其他框架。其中,HttpRequestHandlerAdapter是用來處理流文件的處理器適配器,SimpleServletHandlerAdapter是用來轉接給Sevlet的處理器適配器,RequestMappingHandlerAdapter是用來處理注釋的方法的控制器。
處理器適配器的類結構如下圖2-4所示。
在這個接口中,通過輸入一個處理器對象給supports方法,這個方法就會返回是否支持這個處理器。通過傳入一個HttpServletRequest,HttpServletResponse和一個Hanlder對象給handle方法,這個方法就會傳遞控制權給處理器對象。當處理器對象處理這個HTTP請求后返回數據模型和邏輯視圖名稱的組合對象,處理器適配器會把這個返回結果進而返回給派遣器Servlet。
最后,getLastModified方法是用來處理一個帶有lastModified頭信息的HTTP請求的。不是所有的處理器適配器都需要支持這個方法的。
2.2.4 處理器對象/控制器對象(Handler/Controller)
處理器對象是用于處理業務邏輯的一個基本單元,它通過傳入的HTTP請求對象來決定如何處理業務邏輯和執行哪些服務,執行服務后返回相應的模型數據和邏輯視圖名。一個請求的控制流是由處理器適配器傳遞給處理器對象的,一個類型的處理器對象一定會對應一個支持的處理器適配器。這樣可以實現,處理器適配器和處理器之間的任意匹配,具有靈活的可插拔性。
處理器對象是一個通用的Object類型,控制器類型是最典型的一個處理器類型,控制器的類結構如下圖2-5所示。
控制器是Spring MVC中最簡單的一個處理器,這個處理器有清晰的接口定義,通常這個類型的處理器對象是通過一個簡單控制處理器適配器對象(SimpleControllerHandlerAdapter)來傳遞控制的。
在這個接口中,通過輸入一個HTTP請求對象和一個HTTP響應對象給handleRequest方法,這個方法就會返回一個處理后的模型數據和邏輯視圖名的組合對象。這個對象將通過處理器適配器進而返回給派遣器Servlet。
Spring MVC之所以具有高可擴展性,在于處理器適配器和處理器的設計。這樣可以讓任意的一個處理器對象插入到Spring MVC的體系結構中,使它具有無限的擴展性。
2.2.5 視圖解析器(ViewResolver)
視圖解析器對象用于映射一個邏輯視圖名稱到一個真正的視圖對象。當控制器處理完業務邏輯之后,通常會返回需要顯示的數據模型對象和視圖的邏輯名稱,這樣就需要一個視圖解析器對象通過視圖的邏輯名稱解析出一個真正的視圖對象,然后傳遞控制流給這個視圖對象,由視圖對象展示數據給HTTP的客戶端用戶。
視圖解析器的類結構如圖2-6所示。
在視圖解析器接口中,通過輸入一個邏輯視圖名稱和本地對象(Locale)給resolveViewName方法,這個方法就會返回一個事實上的物理視圖對象。本地對象可以用來查找本地化的資源或者資源包。
2.2.6 視圖(View)
視圖用來把模型數據通過某種顯示方式反饋給客戶,通常是通過執行JSP頁面來完成的。也可以通過其他的更復雜的顯示技術來完成這個展示過程,例如,XML視圖、JSON視圖、JSTL視圖,Tiles視圖,報表視圖和二進制文件視圖等。
視圖的類結構如圖2-7所示。
在視圖接口中,通過輸入HTTP請求對象、HTTP響應對象和一個模型Map對象,這個組件就會把模型Map通過一定的顯示方式輸出到客戶的HTTP響應對象,這就是提供給用戶請求的最終響應。getContentType()能夠返回這個視圖所支持的內容類型,例如,XML, JSON, text/html等。
2.3 本章小結
本章我們學習Spring MVC的實現原理,具體分析了Spring MVC架構中的各個組件、組件的功能以及組件的接口定義,并分析了組件之間的整體交互流程。
從下一章開始,我們將從源碼開始,深入剖析Spring MVC架構的具體實現方法。