DispatcherServlet是Spring MVC的核心内容,了解它的具體服務流程對于中進階應用開發是不可缺少的,下面将通過對源碼進行注釋來分析下DispatcherServlet的流程處理
-
doService
作為分發請求的方法,doService方法的作用和servlet中的doService作用類似,接收http請求,然後提供對應的服務
/**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
* for the actual dispatching.
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
//快照處理,使用快照可以更快響應使用者請求
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
//web IOC容器設定
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
//國際化屬性設定
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
//主體屬性設定
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
//一樣是主題設定
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
//FlashMap開發部分
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
//對部分屬性進行設定完後,開始做請求的分發
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
這個方法中,做了對快照的處理和部分屬性的設定,重要的是所跳轉到的doDispatch方法
-
doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
//設定模型視圖以及異常處理
ModelAndView mv = null;
Exception dispatchException = null;
try {
//設定檔案上傳處了解析器,并對是否為檔案上傳請求進行分析
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//獲得比對的執行器,如果執行器為空,進行錯誤處理
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
//找到對應的執行器-->HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//開始處理請求頭,即對GET或POST請求進行處理
String method = request.getMethod();
boolean isGet = "GET".equals(method);
//GET處理
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//執行攔截器前的方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//執行處理器,傳回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//設定視圖名稱
applyDefaultViewName(processedRequest, mv);
//執行攔截器後的方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//對請求結果做解析,如果是邏輯視圖,則解析名稱,否則不解析,最後渲染視圖
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
//都是對異常的處理方法
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
//釋放資源
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
Dispatch方法的主要流程是:
- 通過請求找到對應的處理鍊,包括攔截器和控制器
- 通過處理器找到對應的擴充卡
- 執行攔截器的事前方法,如果傳回false,則流程結束
- 通過擴充卡運作處理器,傳回模型和視圖
- 對視圖和模型進行處理,執行攔截器事後方法
- 進行視圖和模型的解析操作
-
getHandler
在Dispatch方法中,用到了處理器和攔截器,這也是Dispatch方法的核心,接下來就是獲得處理器的方法getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//周遊HandlerMapping
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
//将獲得的HandlerMapping對象進行轉換HandlerExecutionChain對象
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
HandlerMapping是SpringMVC啟動時初始化的處理器映射,這裡做的操作主要是轉換成HandlerExecutionChain對象,也就是攔截器鍊,成員屬性如下
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
//控制器對象
private final Object handler;
//攔截器數組
private HandlerInterceptor[] interceptors;
//攔截器連結清單
private List<HandlerInterceptor> interceptorList;
//攔截器下标,在對攔截器進行注冊時起定位作用
private int interceptorIndex = -1;
......
}
在這個對象裡用到的成員屬性都是使用HandlerInterceptor聲明的,點進HandlerInterceptor,可以看到有一段對HandlerInterceptor的介紹
* <p>HandlerInterceptor is basically similar to a Servlet Filter, but in
* contrast to the latter it just allows custom pre-processing with the option
* of prohibiting the execution of the handler itself, and custom post-processing.
* Filters are more powerful, for example they allow for exchanging the request
* and response objects that are handed down the chain. Note that a filter
* gets configured in web.xml, a HandlerInterceptor in the application context.
翻譯過來就是:HandlerInterceptor基本上類似于Servlet過濾器,但與後者不同的是,它允許自定義預處理和自定義後處理,比過濾器更強大,例如,它們允許在鍊式進行中傳遞equest和response請求,過濾器是在web.xml中配置的,而攔截器是在application中定義的
這裡的自定義預處理和後處理也就是剛才在Dispatch方法中标注出來的操作
HandlerInterceptor有三個方法
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
分别對應攔截器處理前,處理時,處理後所用到的方法,這就是處理器handler中攔截器的内容
dispatch方法的流程中最後是對視圖進行解析,源碼裡就是processDispatchResult方法對視圖路徑進行解析,對視圖類型進行判斷,比較簡單,就不粘出來了