Spring 是一種企業應用開發框架,在實際開發中起到了應用平臺的做用,有點像企業應用中的「操做系統」,從而爲企業應用資源的使用提供一致的環境。具體來講,Spring 提供的框架特性有 IoC 容器、AOP、事務處理、ORM 等等。在實際的軟件產品開發中,若是有某些特性的使用比較廣泛,那麼就能夠考慮將這些特性做爲框架特性來實現,而後經過框架特性進行有效的封裝,從而提升應用開發效率。 前端
而 Spring MVC 是 Spring 的一種重要模塊,做爲開源的 Java EE 應用框架,不少 Web 應用是由 Spring 來支撐的。在 Web 應用中,MVC 模式的使用已經廣爲人知,若是 Spring 沒有本身實現的 MVC 模式的支持,那麼做爲一個總體解決方法,它是不完整的。 並且對於 Web UI 的開發來講,這也是一種很是不錯的選擇。 下面咱們就慢慢來介紹。web
MVC 是 Model(模型)、View(視圖)以及 Controller(控制器)的縮寫。它是一種經典的軟件架構模式。它最先由 Trygve Reenskaug 在 1978 年提出,是 施樂帕羅奧多研究中心 (Xerox PARC)在 20 世紀 80 年代爲程序語言 Smalltalk 發明的一種軟件架構。MVC 模式的目的是實現一種動態的程序設計,使後續對程序的修改和擴展簡化,而且使程序某一部分的重複利用成爲可能。除此以外,此模式經過對複雜度的簡化,使程序結構更爲直觀。軟件系統經過對自身基本部分分離的同時也賦予了各個基本部分應有的功能。數據庫
MVC 模式在 UI 設計中使用的很是廣泛,在著做《面向模式的軟件體系結構》中,開篇就提到了這個模式。這個模式的主要特色是:分離了模型、視圖、控制器三種角色,將業務處理從 UI 設計中獨立出來,封裝到模型和控制器設計中去,使得它們互相之間解耦,從而能夠獨立擴展而不須要互相依賴。
編程
在 Java 領域最經典的 MVC 實現方式是:JSP + Servlet + Javabean,雖然,如今已經被 HTML + AJAX + Servlet + JSON + POJO 這樣的實現方式所取代。儘管已經有了許多的不一樣,但二者本質仍是同樣的,咱們就以經典模式進行分析。設計模式
在最初的 JSP 網頁中,像數據庫查詢語句(SQL query)這樣的數據層代碼和像 HTML 這樣的表示層代碼是混在一塊兒。雖然經驗比較豐富的開發者會將數據從表示層中分離開來,但這樣的良好設計一般並非很容易作到的,實現它須要精心地計劃以及不斷地嘗試。而 MVC 能夠從根本上強制性地將它們分開,儘管構造 MVC 應用程序須要一些額外的工做,可是它帶給咱們的好處是毋庸置疑的。下面是 MVC 的基本原理圖:瀏覽器
前面已經提過,MVC 模式將一個交換式應用程序分爲三個組件: Model、View 以及 Controller。MVC 模式在概念上強調 Model、View、Controller 的分離,各個模塊也遵循着由 Controller 來處理消息,Model 控制數據源,View 負責數據顯示地職責分離原則,所以在實現上,MVC 模式的 Framework 一般會將 MVC 三個部分分離實現:Model 負責數據訪問,較現代的 Framework 都會建議使用獨立的數據對象(DTO、POCO、POJO等等)來代替弱類型的集合對象。數據訪問的代碼會使用 Data Access 的代碼或是 ORM-based Framework,也能夠進一步使用 Repository Pattern 與 Unit of Works Pattern 來切割數據源的相依性;Controller 負責處理消息,較高級的 Framework 會有一個默認的實現來做爲 Controller 的基礎,例如 Spring 的 DispatcherServlet 或是 ASP.NET MVC 的 Controller 等,在職者分離原則上,每一個 Controller 負責的部分不一樣,所以會將各個 Controller 切割成不一樣的文件以利維護;View 負責顯示數據,這個部分多爲前端應用,而 Controller 會有一個機制將處理的結果 (多是 Model, 集合或是狀態等) 交給 View,而後由 View 來決定怎麼顯示。例如 Spring Framework 使用 JSP 或相應技術,ASP.NET MVC 則使用 Razor 處理數據的顯示。其中,Model 部分是它的核心功能,但在使用上仍是頗爲講究的。服務器
首先,多個 View 能共享一個 Model 。同一個 Web 應用程序會提供多種用戶界面,例如用戶但願既可以經過瀏覽器來收發電子郵件,還但願經過手機來訪問電子郵箱,這就要求 Web 網站同時能提供 Internet 界面或者 WAP 界面。在 MVC 設計模式中, Model 響應用戶請求並返回響應數據,View 負責格式化數據並把它們呈現給用戶,業務邏輯和表示層分離,同一個 Model 能夠被不一樣的 View 重用,因此大大提升了代碼的可重用性。數據結構
其次,Controller 是自包含(self-contained)指高獨立內聚的對象,與 Model 和 View 保持相對獨立,因此能夠方便的改變應用程序的數據層和業務規則。例如,把數據庫從 MySQL 移植到 Oracle,或者把RDBMS 數據源改變成 LDAP 數據源,只需改變 Model 便可。一旦正確地實現了控制器,無論數據來自數據庫仍是 LDAP 服務器,View 都會正確地顯示它們。因爲 MVC 模式的三個模塊相互獨立,改變其中一個不會影響其餘兩個,因此依據這種設計思想能構造良好的少互擾性的構件。架構
此外,Controller 提升了應用程序的靈活性和可配置性。Controller 能夠用來鏈接不一樣的 Model 和 View 去完成用戶的需求,也能夠構造應用程序提供強有力的手段。給定一些可重用的 Model 、 View 和Controller 能夠根據用戶的需求選擇適當的 Model 進行處理,而後選擇適當的的 View 將處理結果顯示給用戶。app
由於 MVC 模式強調職責分離,因此在發展 MVC 應用時會產生出不少文件,在 IDE (集成開發環境) 不夠成熟時它會是個問題,但在現代主流 IDE 都能使用類對象的信息來組織代碼編輯的狀況下,多文件早已不是問題,並且 MVC 模式會要求開發者進一步思考應用程序的架構 (Application Architecture),而非用大雜燴的方式開發應用程序,對於應用程序的生命週期以及後續的可擴充與可維護性而言有至關正面的幫助。另外,MVC 職責分離也帶來了一個現代軟件工程要求的重要特性:可測試性 (Testability),MVC-based 的應用程序在良好的職責分離的設計下,各個部分可獨立行使單元測試,有利用與企業內的自動化測試、持續集成 (Continuous Integration) 與持續發行 (Continuous Delivery) 流程集成,減小應用程序改版部署所需的時間。
MVC 模式的應用程序的目的就是但願打破以往應用程序使用的大雜燴程序撰寫方式,並間接誘使開發人員以更高的架構導向思惟來思考應用程序的設計,所以對於一個剛入門的初學者來講,架構導向的思考會有必定的門檻,須要較多的實現與練習才能具有相應的能力,大多數的初學者仍是較習慣於大雜燴式的程序撰寫,因此可能會對 MVC 模式抱持着排斥或厭惡的心態,然而 MVC (或是其餘的Design Patterns) 都是有助於應用程序長遠的發展,雖然大雜燴式的程序也能夠用來發展長生命週期的應用程序,可是相較於 MVC,大雜燴式的程序在可擴充性和可維護性 (尤爲是可測試性) 上會遠比 MVC 複雜不少,相反的,MVC 模式的應用程序是在初始開發時期必須先思考並使用軟件架構,使得開發時期會須要花較多心力,可是一旦應用程序完成後,可擴充性、可維護性和可測試性反而會由於 MVC 的特性而變得容易。
所以,MVC 模式在已有衆多優秀 Framework 的現代,早就己經沒有不適合小型應用的問題,小型的應用仍是能夠由 MVC Framework 的應用來獲取 MVC 的優勢,同時它也能做爲將來小型應用擴充到大型應用時的基礎與入門磚。若一開始就想要作大型應用,那麼 MVC 模式的職責分離以及要求開發的架構思考會更適合大型應用的開發。
根據需求,Spring 提供了一個 Web 框架,它創建在 Spring 的核心概念 —— IoC 的應用上下文之上,並將其擴展到 Web 環境,與中間層應用上下文之間無縫結合。因爲 Spring 的分層架構,Spring 中間層上下文也能輕易地集成到各類不一樣的 Web 框架中。固然,要達到這樣的分層架構,中間層的接口設計就是相當重要的了。
Spring 和專用 Web 框架(例如 Struts、WebWork 和 Tapestry)之間最根本的區別是:Spring 將它的 Web MVC 框架做爲整體方案架構的一部分,所以它被設計爲鬆散耦合,而且無縫地和 Spring 中間層豐富的 IoC 和 AOP 管理功能融爲了一體,這也是 Spring MVC 的特色。
最初的 J2EE Web 層實現一般是:在 JSP 頁中包含過多的 Java 腳本(scriptlet),其中混亂地雜合了表達和業務邏輯。它致使的結果是一個不可測試的表現層、使人頭痛的重構,以及維護的地獄。即便不是大多數,至少也有許多 J2EE Web 開發者在缺乏經驗時實現了這樣的應用程序;而更多的人是接手維護和升級了這樣的代碼,並惱怒地咒罵最初的開發者。
最原始的以 JSP 爲中心的編程模型出自 ASP 和 PHP,這是 1996 年以後流行的兩個 Web 編程環境。在這兩個環境中,以頁面爲中心的腳本是僅有的選擇,沒法輕鬆實現分開流程控制和視圖呈現,也沒法輕鬆地將業務委派給邏輯組件。在 ASP.NET 和 PHP4 以後,它們都有了很大的改進,都爲應用程序架構提供了更好的選擇,惋惜傳統的編程模型仍然有着很大的影響力。
因此,在一個分層體系的 J2EE 應用程序中,Web 層結構應該比這樣的腳本頁面更好,這樣就能夠像中間層組件同樣有着可維護性、可測試性和可重用性。
Spring MVC 框架是一個基於請求驅動的 Web 框架,而且也使用了前端控制器模式來進行設計,再根據請求映射規則發送給相應的頁面控制器(動做/處理器)進行處理。下面是 Spring MVC 處理請求的流程:
具體執行步驟以下:
一、首先用戶發送請求——前端控制器,前端控制器根據請求信息(如 URL)來決定選擇哪個頁面控制器進行處理並把請求委託給它,即之前的控制器的控制邏輯部分也就是一、2步驟;
二、頁面控制器接收到請求後,進行功能處理,首先須要收集和綁定請求參數到一個對象,這個對象在 Spring MVC 中叫 命令對象,並進行驗證,而後命令對象委託給業務對象進行處理;處理完畢後返回一個 ModelAndView(模型數據和邏輯視圖名),也就是三、四、5步驟;
三、前端控制器收回控制權,而後根據返回的邏輯視圖名,選擇相應的視圖進行渲染,並把模型數據傳入以便視圖渲染,步驟六、7;
四、前端控制器再次收回控制權,將響應返回給用戶,從8到整個結束。
爲完成以上的具體執行步驟,Spring MVC 將各個角色的職責進行了清晰的劃分:前端控制器(DispatcherServlet)、請求處處理器映射(HandlerMapping)、處理器適配器(HandlerAdapter)、視圖解析器(ViewResolver)、處理器或頁面控制器(Controller)、驗證器(Validator)、命令對象(Command 命令對象)、表單對象(Form Object 表單對象)。
它的核心開發步驟是:
一、DispatcherServlet 在 web.xml 中的部署描述,從而攔截請求到 Spring MVC;
二、HandlerMapping 的配置,從而將請求映射處處理器;
三、HandlerAdapter 的配置,從而支持多種類型的處理器;
四、ViewResolver 的配置,從而將邏輯視圖名解析爲具體視圖技術;
五、Controller 的配置,從而進行功能處理。
下面是 Spring MVC 核心架構:
核心架構的具體步驟以下:
一、首先用戶發送請求——DispatcherServlet,前端控制器收到請求後本身不進行處理,而是委託給其餘的解析器進行處理,做爲統一訪問點,進行全局的流程控制;
二、DispatcherServlet——HandlerMapping,HandlerMapping 將會把請求映射爲 HandlerExecutionChain 對象(包含一個 Handler 處理器(頁面控制器)對象、多個 HandlerInterceptor 攔截器)對象,經過這種策略模式,很容易添加新的映射策略;
三、DispatcherServlet——HandlerAdapter,HandlerAdapter 將會把處理器包裝爲適配器,從而支持多種類型的處理器,即適配器設計模式的應用,從而很容易支持不少類型的處理器;
四、HandlerAdapter——處理器功能處理方法的調用,HandlerAdapter 將會根據適配的結果調整真正的處理器的功能處理方法,完成功能處理;並返回一個 ModelAndView 對象(包含 模型數據、邏輯視圖名);
五、ModelAndView 的邏輯視圖名——ViewResoler,ViewResoler 將吧邏輯視圖名解析爲具體的 View,經過這種策略模式,很容易更換其餘視圖技術;
六、View——渲染,View 會根據傳進來的 Model 模型數據進行渲染,此處的 Model 實際是一個 Map 數據結構,所以很容易支持其餘視圖技術;
七、返回控制權給 DispatcherServlet,由 DispatcherServlet 返回響應給用戶,到此一個流程結束。
好了,至此架構方面就講完了,再往下就是源碼分析了。
——水門(2016年3月寫於武漢)