深入底層,仿SpringMVC自己寫框架
前言:
前面的文章我們介紹過如何自己寫一個MyBatis框架:
今天我們來寫一個SpringMVC框架,相比於寫MyBatis框架,SpringMVC要簡單一些,只需要xml解析+反射就可以完成,不需要jdk動態代理。
廢話不多說,直接開始摟乾貨。
要自己寫框架,必須理解框架的底層原理和運行機制。那麼我們首先來回顧SpringMVC的實現原理。
SpringMVC實現原理:
核心組件:
1.DispatcherServlet:前端控制器,是整個流程式控制制的核心,控制其他組件的執行,統一調度,降低組件之間的耦合性,相當於總指揮。
2.Handler:處理器,完成具體業務邏輯,相當於Servlet或Action。
3.HandlerMapping:DispatcherServlet接收到請求之後,通過HandlerMapping將不同的請求分發到不同的Handler。
4.HandlerInterceptor:處理器攔截器,是一個介面,如果我們需要做一些攔截處理,可以來實現這個介面。
5.HandlerExecutionChain:處理器執行鏈,包括兩部分內容:Handler和HandlerInterceptor(系統會有一個默認的HandlerInterceptor,如果需要額外攔截處理,可以添加攔截器設置)。
6.HandlerAdapter:處理器適配器,Handler執行業務方法之前,需要進行一系列的操作包括表單數據的驗證,數據類型的轉換,將表單數據封裝到JavaBean等等,這一系列的操作,都是由HandlerAdapter來完成,DispatcherServlet通過HandlerAdapter執行不同的Handler。
7.ModelAndView:裝載了模型數據和視圖信息,作為Handler的處理結果,返回給DispatcherServlet。
8.ViewResolver:視圖解析器,DispatcherServlet通過它將邏輯視圖解析成物理視圖,最終將渲染結果響應給客戶端。
以上就是SpringMVC的核心組件。那麼這些組件之間是如何進行交互的呢?
我們來看SpringMVC的實現流程:
1.客戶端請求被DispatcherServlet(前端控制器)接收。
2.根據HandlerMapping映射到Handler。
3.生成Handler和HandlerInterceptor(如果有則生成)。
4.Handler和HandlerInterceptor以HandlerExecutionChain的形式一併返回給DispatcherServlet。
5.DispatcherServlet通過HandlerAdapter調用Handler的方法做業務邏輯處理。
6.返回一個ModelAndView對象給DispatcherServlet。
7.DispatcherServlet將獲取的ModelAndView對象傳給ViewResolver視圖解析器,將邏輯視圖解析成物理視圖View。
8.ViewResolver返回一個View給DispatcherServlet。
9.DispatcherServlet根據View進行視圖渲染(將模型數據填充到視圖中)。
10.DispatcherServlet將渲染後的視圖響應給客戶端。
通過以上的分析,大致可以將SpringMVC流程理解如下:
首先需要一個前置控制器DispatcherServlet,作為整個流程的核心,由它去調用其他組件,共同完成業務。主要組件有兩個:一是Controller,調用其業務方法Method,執行業務邏輯。二是ViewResolver視圖解析器,將業務方法的返回值解析為物理視圖+模型數據,返回客戶端。
我們自己寫框架就按照這個思路來。
初始化工作:
1.根據Spring IOC的思路,需要將參與業務的對象全部創建並保存,供流程調用。所以首先我們需要創建Controller對象,HTTP請求是通過註解找到對應的Controller對象,所以我們需要將所有的Controller與其註解建立關聯,很顯然,使用key-value結構的Map集合來保存最合適不過了,這樣就模擬了IOC容器。
2.Controller的Method也是通過註解與HTTP請求映射的,同樣的,我們需要將所有的Method與其註解建立關聯,HTTP直接通過註解的值找到對應的Method,這裡也用Map集合保存。
3.實例化視圖解析器。
初始化工作完成,接下來處理HTTP請求,業務流程如下:
1.DispatcherServlet接收請求,通過映射從IOC容器中獲取對應的Controller對象。
2.根據映射獲取Controller對象對應的Method。
3.調用Method,獲取返回值。
4.將返回值傳給視圖解析器,返回物理視圖。
5.完成頁面跳轉。
思路捋清楚了,接下來開始寫代碼,我們需要創建以下類:
1.MyDispatcherServlet:模擬DispatcherServlet。
2.MyController:模擬Controller註解。
3.MyRequestMapping:模擬RequestMapping註解。
4.MyViewResolver:模擬ViewResolver視圖解析器。
創建MyDispatcherServlet,init方法完成初始化:
1.將Controller與註解進行關聯,保存到iocContainer中。
哪些Controller是需要添加到iocContainer中的?
必須同時滿足兩點:
1.springmvc.xml中配置掃描的類。
2.類定義處添加了註解。
注意這兩點必須同時滿足。
代碼思路:
(1)解析springmvc.xml。
(2)獲取component-scan標籤配置的包下的所有類。
(3)判斷若這些類添加了@MyController註解,則創建實例對象,並且保存到iocContainer。
(4)@MyRequestMapping的值為鍵,Controller對象為值。
2.將Controller中的Method與註解進行關聯,保存到handlerMapping中。
代碼思路:
(1)遍歷iocContainer中的Controller實例對象。
(2)遍歷每一個Controller對象的Method。
(3)判斷Method是否添加了@MyRequestMapping註解,若添加,則進行映射並保存。
(4)保存到handlerMapping中,@MyRequestMapping的值為鍵,Method為值。
3.實例化ViewResolver。
代碼思路:
(1)解析springmvc.xml。
(2)根據bean標籤的class屬性獲取需要實例化的MyViewResolver。
(3)使用反射創建實例化對象,同時獲取prefix和suffix屬性,以及setter方法。
(4)使用反射調用setter方法給屬性賦值,完成MyViewResolver的實例化。
doPost方法處理HTTP請求:
1.解析HTTP,分別得到Controller和Method對應的uri。
2.通過uri分別在iocContainer和handlerMapping中獲取對應的Controller以及Method。
3.使用反射調用Method,執行業務方法,獲取結果。
4.結果傳給MyViewResolver進行解析,返回真正的物理視圖(JSP頁面)。
5.完成JSP的頁面跳轉。
代碼:
1.創建MyController註解,作用目標為類。
2.創建MyRequestMapping註解,作用目標為類和方法。
3.創建MyDispatcherServlet,核心控制器,init完成初始化工作,doPost處理HTTP請求。
4.創建視圖解析器MyViewResolver。
5.創建TestController,處理業務請求。
6.測試。
跳轉index.jsp,同時控制台列印業務日誌,訪問成功。
源碼:
github
https://github.com/southwind9801/SpringMVCImitate.git
專業 熱愛 專註
致力於最高效的Java學習
Java大聯盟
TAG:Java大聯盟 |