看透 Spring MVC 源代碼分析與實踐 —— Spring MVC 組件分析

由於星期一接到面試通知,和麪試官約好了星期四面試,所以這幾天沒更新完這系列的文章,面完試後立馬就把這個解決掉。通過這次面試,也讓我懂得了很多,知道了自己的一些不足之處,後面還要繼續下功夫好好的深入複習下去。這幾篇文章寫的我覺得還是不夠仔細,感興趣的還是建議自己去看看源碼。

第 11 章 —— 組件概覽

HandlerMapping

根據 request 找到對應的處理器 Handler 和 Interceptors。內部只有一個方法

1
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

HandlerAdapter

Handler 適配器,內部方法如下:

1
2
3
boolean supports(Object handler);//判斷是否可以使用某個 Handler
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; //具體使用
long getLastModified(HttpServletRequest request, Object handler);//獲取資源上一次修改的時間

HandlerExceptionResolver

根據異常設置 ModelAndView ,再交給 render 方法進行渲染。

1
2
ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex)

ViewResolver

用來將 String 類型的視圖名和 Locale 解析爲 View 類型的視圖。

1
View resolveViewName(String viewName, Locale locale) throws Exception;

它的一個實現類 BeanNameViewResolver,它重寫 resolveViewName 方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public View resolveViewName(String viewName, Locale locale) throws BeansException {
ApplicationContext context = getApplicationContext();
//如果應用上下文沒有找到視圖,返回 null
if (!context.containsBean(viewName)) {
if (logger.isDebugEnabled()) {
logger.debug("No matching bean found for view name '" + viewName + "'");
}
// Allow for ViewResolver chaining...
return null;
}
//如果找到的視圖類型不匹配,也返回 null
if (!context.isTypeMatch(viewName, View.class)) {
if (logger.isDebugEnabled()) {
logger.debug("Found matching bean for view name '" + viewName +
"' - to be ignored since it does not implement View");
}
// Since we're looking into the general ApplicationContext here,
// let's accept this as a non-match and allow for chaining as well...
return null;
}
//根據視圖名稱從 Spring 容器中查找 Bean,返回找到的 bean
return context.getBean(viewName, View.class);
}

RequestToViewNameTranslator

獲取 request 中的視圖名。接口裏面也是隻有一個方法:

1
String getViewName(HttpServletRequest request) throws Exception; //根據 request 查找視圖名

LocaleResolver

用於從 request 解析出 Locale。

1
2
3
4
5
6
public interface LocaleResolver {
//從 request 解析出 Locale
Locale resolveLocale(HttpServletRequest request);
//根據 request 設置 locale
void setLocale(HttpServletRequest request, HttpServletResponse response, @Nullable Locale locale);
}

ThemeResolver

解析主題

1
2
3
4
5
6
public interface ThemeResolver {
//通過給定的 request 查找主題名
String resolveThemeName(HttpServletRequest request);
//根據給定的 request 設置主題名
void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName);
}

在 RequestContext.java 文件中可以獲取主題:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public String getThemeMessage(String code, String defaultMessage) {
//獲取主題的信息
return getTheme().getMessageSource().getMessage(code, null, defaultMessage, this.locale);
}
public Theme getTheme() {
//判斷主題是否爲空
if (this.theme == null) {
// 通過 RequestContextUtils 獲取 request 中的主題名
this.theme = RequestContextUtils.getTheme(this.request);
if (this.theme == null) { //如果還是爲空的話
//那就是沒有有效的主題解析器和主題
this.theme = getFallbackTheme();
}
}
return this.theme;
}

RequestContextUtils.getTheme() 方法:

1
2
3
4
5
6
7
8
9
10
11
public static Theme getTheme(HttpServletRequest request) {
ThemeResolver themeResolver = getThemeResolver(request);
ThemeSource themeSource = getThemeSource(request);
if (themeResolver != null && themeSource != null) {
String themeName = themeResolver.resolveThemeName(request);
return themeSource.getTheme(themeName);
}
else {
return null;
}
}

MultipartResolver

用於處理上傳請求,處理方法:將普通的 request 包裝成 MultipartHttpServletRequest

1
2
3
4
5
6
7
8
public interface MultipartResolver {
//根據 request 判斷是否是上傳請求
boolean isMultipart(HttpServletRequest request);
//將 request 包裝成 MultipartHttpServletRequest
MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException;
//清理上傳過程中產生的臨時資源
void cleanupMultipart(MultipartHttpServletRequest request);
}

FlashMapManager

FlashMap 主要在 redirect 中傳遞參數,FlashMapManager 用來管理 FlashMap 的。

1
2
3
4
5
6
7
public interface FlashMapManager {
//恢復參數,並將恢復過的和超時的參數從保存介質中刪除
@Nullable
FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);
//將參數保存起來
void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}

小結

介紹 Spring MVC 中九大組件的接口、作用、內部方法實現及作用進行了簡單的介紹,詳細的還需大家自己去看源碼。

總結

Spring MVC 原理總結

本質是一個 Servlet,這個 Servlet 繼承自 HttpServlet。Spring MVC 中提供了三個層次的 Servlet:HttpServletBean、FrameworkServlet 和 DispatcherServlet。他們相互繼承, HttpServletBean 直接繼承自 Java 的 HttpServlet。HttpServletBean 用於將 Servlet 中的 Servlet 中配置的參數設置到相應的屬性中,FrameworkServlet 初始化了 Spring MVC 中所使用的 WebApplicationContext,具體處理請求的 9 大組件是在 DispatcherServlet 中初始化的,整個繼承圖如下:

spring-mvc1

原文鏈接:看透 Spring MVC 源代碼分析與實踐 —— Spring MVC 組件分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章