程式設計筆記詳解——SpringMVC 工作原理
先來看一下什麼是 MVC 模式
MVC 是一種設計模式.
MVC 的原理圖如下:

SpringMVC 簡單介紹
SpringMVC 框架是以請求為驅動,圍繞 Servlet 設計,將請求發給控制器,然後通過模型物件,分派器來展示請求結果檢視。其中核心類是 DispatcherServlet,它是一個 Servlet,頂層是實現的Servlet介面。
SpringMVC 使用
需要在 web.xml 中配置 DispatcherServlet 。並且需要配置 Spring 監聽器ContextLoaderListener
org.springframework.web.context.ContextLoaderListener
springmvc
org.springframework.web.servlet.DispatcherServlet
<!-- 如果不設定init-param標籤,則必須在/WEB-INF/下建立xxx-servlet.xml檔案,其中xxx是servlet-name中配置的名稱。 -->
contextConfigLocation
classpath:spring/springmvc-servlet.xml
1
springmvc
/
SpringMVC 工作原理(重要)
簡單來說:
客戶端傳送請求-> 前端控制器 DispatcherServlet 接受客戶端請求 -> 找到處理器對映 HandlerMapping 解析請求對應的 Handler-> HandlerAdapter 會根據 Handler 來呼叫真正的處理器開處理請求,並處理相應的業務邏輯 -> 處理器返回一個模型檢視 ModelAndView -> 檢視解析器進行解析 -> 返回一個檢視物件->前端控制器 DispatcherServlet 渲染資料(Moder)->將得到檢視物件返回給使用者
如下圖所示:

SpringMVC執行原理
上圖的一個筆誤的小問題:Spring MVC 的入口函式也就是前端控制器 DispatcherServlet 的作用是接收請求,響應結果。
流程說明(重要):
(1)客戶端(瀏覽器)傳送請求,直接請求到 DispatcherServlet。
(2)DispatcherServlet 根據請求資訊呼叫 HandlerMapping,解析請求對應的 Handler。
(3)解析到對應的 Handler(也就是我們平常說的 Controller 控制器)後,開始由 HandlerAdapter 介面卡處理。
(4)HandlerAdapter 會根據 Handler 來呼叫真正的處理器開處理請求,並處理相應的業務邏輯。
(5)處理器處理完業務後,會返回一個 ModelAndView 物件,Model 是返回的資料物件,View 是個邏輯上的 View。
(6)ViewResolver 會根據邏輯 View 查詢實際的 View。
(7)DispaterServlet 把返回的 Model 傳給 View(檢視渲染)。
(8)把 View 返回給請求者(瀏覽器)
SpringMVC 重要元件說明
1、前端控制器DispatcherServlet(不需要工程師開發),由框架提供(重要)
作用: Spring MVC 的入口函式。接收請求,響應結果,相當於轉發器,中央處理器。有了 DispatcherServlet 減少了其它元件之間的耦合度。使用者請求到達前端控制器,它就相當於mvc模式中的c,DispatcherServlet是整個流程控制的中心,由它呼叫其它元件處理使用者的請求,DispatcherServlet的存在降低了元件之間的耦合性。
2、處理器對映器HandlerMapping(不需要工程師開發),由框架提供
作用:根據請求的url查詢Handler。HandlerMapping負責根據使用者請求找到Handler即處理器(Controller),SpringMVC提供了不同的對映器實現不同的對映方式,例如:配置檔案方式,實現介面方式,註解方式等。
3、處理器介面卡HandlerAdapter
作用:按照特定規則(HandlerAdapter要求的規則)去執行Handler
通過HandlerAdapter對處理器進行執行,這是介面卡模式的應用,通過擴充套件介面卡可以對更多型別的處理器進行執行。
4、處理器Handler(需要工程師開發)
注意:編寫Handler時按照HandlerAdapter的要求去做,這樣介面卡才可以去正確執行Handler
Handler 是繼DispatcherServlet前端控制器的後端控制器,在DispatcherServlet的控制下Handler對具體的使用者請求進行處理。
由於Handler涉及到具體的使用者業務請求,所以一般情況需要工程師根據業務需求開發Handler。
5、檢視解析器View resolver(不需要工程師開發),由框架提供
作用:進行檢視解析,根據邏輯檢視名解析成真正的檢視(view)
View Resolver負責將處理結果生成View檢視,View Resolver首先根據邏輯檢視名解析成物理檢視名即具體的頁面地址,再生成View檢視物件,最後對View進行渲染將處理結果通過頁面展示給使用者。 springmvc框架提供了很多的View檢視型別,包括:jstlView、freemarkerView、pdfView等。
一般情況下需要通過頁面標籤或頁面模版技術將模型資料通過頁面展示給使用者,需要由工程師根據業務需求開發具體的頁面。
6、檢視View(需要工程師開發)
View是一個介面,實現類支援不同的View型別(jsp、freemarker、pdf…)
注意:處理器Handler(也就是我們平常說的Controller控制器)以及檢視層view都是需要我們自己手動開發的。其他的一些元件比如:前端控制器DispatcherServlet、處理器對映器HandlerMapping、處理器介面卡HandlerAdapter等等都是框架提供給我們的,不需要自己手動開發。
DispatcherServlet詳細解析
首先看下原始碼:
packageorg.springframework.web.servlet;
@SuppressWarnings("serial")
publicclassDispatcherServletextendsFrameworkServlet{
publicstaticfinalString MULTIPART_RESOLVER_BEAN_NAME ="multipartResolver";
publicstaticfinalString LOCALE_RESOLVER_BEAN_NAME ="localeResolver";
publicstaticfinalString THEME_RESOLVER_BEAN_NAME ="themeResolver";
publicstaticfinalString HANDLER_MAPPING_BEAN_NAME ="handlerMapping";
publicstaticfinalString HANDLER_ADAPTER_BEAN_NAME ="handlerAdapter";
publicstaticfinalString HANDLER_EXCEPTION_RESOLVER_BEAN_NAME ="handlerExceptionResolver";
publicstaticfinalString REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME ="viewNameTranslator";
publicstaticfinalString VIEW_RESOLVER_BEAN_NAME ="viewResolver";
publicstaticfinalString FLASH_MAP_MANAGER_BEAN_NAME ="flashMapManager";
publicstaticfinalString WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() +".CONTEXT";
publicstaticfinalString LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() +".LOCALE_RESOLVER";
publicstaticfinalString THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() +".THEME_RESOLVER";
publicstaticfinalString THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() +".THEME_SOURCE";
publicstaticfinalString INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() +".INPUT_FLASH_MAP";
publicstaticfinalString OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() +".OUTPUT_FLASH_MAP";
publicstaticfinalString FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() +".FLASH_MAP_MANAGER";
publicstaticfinalString EXCEPTION_ATTRIBUTE = DispatcherServlet.class.getName() +".EXCEPTION";
publicstaticfinalString PAGE_NOT_FOUND_LOG_CATEGORY ="org.springframework.web.servlet.PageNotFound";
privatestaticfinalString DEFAULT_STRATEGIES_PATH ="DispatcherServlet.properties";
protectedstaticfinalLog pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
privatestaticfinalProperties defaultStrategies;
static{
try{
ClassPathResource resource =newClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch(IOException ex) {
thrownewIllegalStateException("Could not load 'DispatcherServlet.properties': "+ ex.getMessage());
}
}
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */
privatebooleandetectAllHandlerMappings =true;
/** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */
privatebooleandetectAllHandlerAdapters =true;
/** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */
privatebooleandetectAllHandlerExceptionResolvers =true;
/** Detect all ViewResolvers or just expect "viewResolver" bean? */
privatebooleandetectAllViewResolvers =true;
/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
privatebooleanthrowExceptionIfNoHandlerFound =false;
/** Perform cleanup of request attributes after include request? */
privatebooleancleanupAfterInclude =true;
/** MultipartResolver used by this servlet */
privateMultipartResolver multipartResolver;
/** LocaleResolver used by this servlet */
privateLocaleResolver localeResolver;
/** ThemeResolver used by this servlet */
privateThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet */
privateList handlerMappings;
/** List of HandlerAdapters used by this servlet */
privateList handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet */
privateList handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet */
privateRequestToViewNameTranslator viewNameTranslator;
privateFlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet */
privateList viewResolvers;
publicDispatcherServlet(){
super();
}
publicDispatcherServlet(WebApplicationContext webApplicationContext){
super(webApplicationContext);
}
@Override
protectedvoidonRefresh(ApplicationContext context){
initStrategies(context);
}
protectedvoidinitStrategies(ApplicationContext context){
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}
DispatcherServlet類中的屬性beans:
HandlerMapping:用於handlers對映請求和一系列的對於攔截器的前處理和後處理,大部分用@Controller註解。
HandlerAdapter:幫助DispatcherServlet處理對映請求處理程式的介面卡,而不用考慮實際呼叫的是 哪個處理程式。- - -
ViewResolver:根據實際配置解析實際的View型別。
ThemeResolver:解決Web應用程式可以使用的主題,例如提供個性化佈局。
MultipartResolver:解析多部分請求,以支援從HTML表單上傳檔案。-
FlashMapManager:儲存並檢索可用於將一個請求屬性傳遞到另一個請求的input和output的FlashMap,通常用於重定向。
在Web MVC框架中,每個DispatcherServlet都擁自己的WebApplicationContext,它繼承了ApplicationContext。WebApplicationContext包含了其上下文和Servlet例項之間共享的所有的基礎框架beans。
HandlerMapping

HandlerMapping
HandlerMapping介面處理請求的對映HandlerMapping介面的實現類:
SimpleUrlHandlerMapping類通過配置檔案把URL對映到Controller類。
DefaultAnnotationHandlerMapping類通過註解把URL對映到Controller類。
HandlerAdapter

HandlerAdapter
HandlerAdapter介面-處理請求對映
AnnotationMethodHandlerAdapter:通過註解,把請求URL對映到Controller類的方法上。
HandlerExceptionResolver

HandlerExceptionResolver
HandlerExceptionResolver介面-異常處理介面
SimpleMappingExceptionResolver通過配置檔案進行異常處理。
AnnotationMethodHandlerExceptionResolver:通過註解進行異常處理。
ViewResolver

ViewResolver
ViewResolver介面解析View檢視。
UrlBasedViewResolver類 通過配置檔案,把一個檢視名交給到一個View來處理。