談談你對Spring MVC中的九大組件的理解?
一位應屆畢業生被問到這樣一道面試題,說談談你對Spring MVC中的九大組件的理解。
今天,我給大家分享一下我的理解。
1、Spring MVC九大組件
使用Spring MVC框架時,它的主要入口是DispatcherServlet類,Spring MVC子容器初始化時,會調用DispatcherServlet的onRefresh()方法,而onRefresh()方法只做了一件事,就是調用initStrategies()方法來初始化Spring MVC的九大組件,如源碼所示:
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
顧名思義,initStrategies()方法直譯過來就是初始化策略,Spring MVC把九大組件設計成九大策略,其實就是為了明確各個組件的職責,達到解耦的目的。
Spring MVC的九大組件按照初始化順序分別為:MultipartResolver多文件上傳組件、LocaleResolver多語言支持組件、ThemeResolver主題模板處理組件、HandlerMappings URL映射組件、HandlerAdapters業務邏輯適配組件、HandlerExceptionResolvers異常處理組件、RequestToViewNameTranslator視圖名稱提取組件、ViewResolvers視圖渲染組件和FlashMapManager閃存管理組件。
下面給大家詳細分析一下,每個組件的功能和職責。
1、MultipartResolver 多文件上傳組件。
用于支持多文件上傳,如代碼所示:
<form method="post" enctype="multipart/form-data" >
<input type="file"/>
<input type="file"/>
<input type="file"/>
<button type="submit">上傳</button>
</form>
主要邏輯就是將enctype為"multipart/form-data"的表單request請求包裝成MultipartHttpServletRequest。程序員在開發的時候,只需要調用MultipartHttpServletRequest的 getFile()方法,就可以獲取客戶端上傳的文件列表了。
2、LocaleResolver多語言支持組件。
用于支持國際化多語言切換,LocaleResolver的主要作用就是從 request 中解析出 local 參數的值,如源碼所示:
public interface LocaleResolver {
Locale resolveLocale(HttpServletRequest request);
void setLocale(HttpServletRequest request, HttpServletResponse response, Locale local);}
}
resolveLocale()方法是從 request 中解析出 local,setLocale()方法是將指定的 local 值設置到 request 中。而 local 大多數情況下都是用來做國際化處理的,配合多語言字典properties來使用,例如中國的Local值為zh_CN。
3、ThemeResolver主題模板處理組件。
主要用于支持Web頁面的多主題風格。可以通過ThemeResolver來讀取和解析頁面主題樣式配置。實現原理和LocaleResolver類似,也是配置一套 properties 文件,根據不同參數來切換讀取;當然,使用ThemeResolver也是可以實現國際化。如源代碼所示:
public interface ThemeResolver {
String resolveThemeName(HttpServletRequest request);
void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName);
}
它的主要方法也和LocaleResolver類似,一個從request提取主題名稱的方法,一個設定主題名稱的方法。
4、HandlerMappingURL映射組件。
主要是用來保存Url和業務邏輯的對應關系,它本質上就是一個Map,Key為URL值就是對應Controller中配置了@RequestMapping注解的方法。但是在Spring源碼中,被封裝成了一個HandlerMapping對象。然后,每個HandlerMapping對象都被緩存在一個List中。如源碼所示:
private List<HandlerMapping> handlerMappings;
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
...
}
5、HandlerAdapter業務邏輯適配組件。
主要功能是動態解析參數以及動態適配業務邏輯對應的Handler,如源碼所示:
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
在HandlerAdapter中提供了一個叫做handle()這樣一個方法,第三個參數 Object handler 第三個參數其實就是業務處理器。在DispatcherServlet中的doDispath()方法中被調用。而handler對象就是根據用戶請求的Url從HandlerMapping獲取的HandlerMapiping對象。
在HandlerApdater的handle()方法中,首先會動態解析用戶傳過來的參數,并完成數據類型轉化。然后,反射調用HandlerMapiping封裝的Controller中的方法,最后,將調用方法的返回結果統一封裝為ModelAndView。
6、HandlerExceptionResolver異常處理組件。
主要用于攔截對不同異常的個性化處理,Spring可以給不同的異常配置不同的ModelAndView,HandlerExceptionResolver根據異常類型,的將處理封裝為一個ModelAndView從而將異常信息轉換為更加友好的Web頁面展示,如源碼所示:
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
HandlerExceptionResolver組件只有一個方法,就是將異常解析為ModelAndView。
當然,HandlerExceptionResolver自己發生異常或者在異常頁面渲染過程中發生異常HandlerExceptionResolver不會處理。Spring可以配置一個全局的500頁面或者404頁面來處理這個問題。
7、RequestToViewNameTranslator視圖名稱提取組件。
這個組件的主要功能是可從request中提取viewName。這個viewName設置在url參數上,也可以設置在request的header上。如源碼所示:
public interface RequestToViewNameTranslator {
String getViewName(HttpServletRequest request) throws Exception;
}
這個其實還是挺有意思的,就是將 request 請求轉換為視圖名稱。它只有一個getViewName()方法。
8、ViewResolvers視圖渲染組件。
它的作用相當于模板引擎,就是根據視圖名稱找到視圖對應的模板文件,然后進行解析,如源碼所示:
public interface ViewResolver {
View resolveViewName(String viewName, Locale local) throws Exception;
}
ViewResolvers組件只有一個resolveViewName()方法,
我們看到resolveViewName()方法有兩個參數。
第一個參數viewName,是String類型,它其實就是視圖名稱,對應的就是模板文件的名稱。第二個參數local,前面我們講過代表的是本地語言環境,可以用來做國際化。
resolveViewName()方法的放回值是一個View對象。而View對象就是用來渲染頁面的,也就是說將程序返回的結果填入到具體的模板里面,生成具體的視圖文件,比如:jsp,ftl,html 等等。
9、FlashMapManage閃存管理組件。
它相當于一個參數緩存器,用來保證請求跳轉過程中參數不丟失,和Struts 2中的ValueStack值棧非常類似。主要是 redirect重定向的時候,參數傳遞會丟失,FlashMapManage就能大顯身手,可以做到Redirect重定向和Forward轉發同樣的效果,如源碼所示:
public interface FlashMapManager {
FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);
void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}
FlashMapManage主要有兩個方法,
retrieveAndUpdate()方法是用來恢復參數的,而且對于恢復過的和超時的參數都會被刪除掉。saveOutputFlashMap() 這個方法是用來保存參數的。
FlashMapManager默認會將參數保存在 Session 中,在日常開發中,如果不想將參數暴露在 Url路徑中,那就可以在請求轉發時,在參數中添加@RedirectAttributes注解將參數緩存,然后在下一個處理器中就可以獲取到。
以上就是我對Spring MVC中的九大組件的理解。
需要注意的是ModelAndView和View并不屬于MVC的九大組件之中,ModelAndView只是對ViewName和Model的封裝,然后作為返回值把信息反饋給用戶。并沒有包含任何執行邏輯。而View只是對模板文件的封裝,它是用作參數來傳遞。