SpringMVC doDispatch方法的基本思路梳理
在分析之前,先介紹一個類
1、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;
該類中主要包括了一個用於處理request的handler,以及和request相關的一系列攔截器interceptors.
進入正題,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 {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
/*
分析1,其目的是:得到包含了用於處理request的HandlerMethod、Interceptors。
*/
mappedHandler = this.getHandler(processedRequest, false);
//如果沒有,則說明沒有處理器能夠處理該request,因此返回404錯誤。
if(mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
/*
分析2,其目的是:得到與Handler匹配的HandlerAdapter。
*/
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if(isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if(this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
/*
分析3:執行所有註冊攔截器的preHandler方法
*/
if(!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
//前面的第一步就是找到用於處理request的handler,到這裏才真正意思上的執行用於處理request的handler方法。具體後面進行分析
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
} finally {
if(asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
this.applyDefaultViewName(request, mv);
/*
分析4:執行所有註冊攔截器的postHandler方法
*/
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var27) {
dispatchException = var27;
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception var28) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var28);
} catch (Error var29) {
this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var29);
}
} finally {
if(asyncManager.isConcurrentHandlingStarted()) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
} else {
if(multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
}
doDispatch方法主要邏輯如下:
1)找到用於處理request的handler和interceptors,構造成一個HandlerExecutionChain.
2) 找到與用於處理request的handler相匹配的HandlerAdapter,目的是:後續將使用此HandlerAdapter來執行handler。
3)執行所有註冊攔截器的preHandler方法
4)真正意思上的執行用於request的handler方法,得到ModelAndView
5)倒序執行所有註冊攔截器的postHandler方法。
6)解析並返回ModelAndView
主要是理清思路,本篇博文將依次分析除第4點之外的幾點。
分析1:找到用於處理request的handler和interceptors,構造成一個HandlerExecutionChain.
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
該函數的功能爲:遍歷DispatcherServlet中的private List handlerMappings; 看哪個HandlerMapping能夠處理該request,則返回由
AbstractHandlerMapping.java
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);//第一步
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//第二步
return getHandlerExecutionChain(handler, request);
}
此方法的主要邏輯如下:
第一步:根據request中的url得到相應的handler,此handler爲HandlerMethod的實例。
第二步:將第一步得到的HandlerMethod作爲參數實例化一個HandlerExecutionChain對象。在實例化過程中,還需要得到與request相關的Interceptors。
下面將逐一的分析這兩步所涉及到具體實現。
先看第一步:根據request中的url得到相應的handler,此handler爲HandlerMethod的實例
getHandlerInternal方法的代碼如下:
AbstractHandlerMethodMapping.java
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
//得到與request相關的handlerMethod,如何得到的,就是在Map中來尋找
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
getHandlerInternal函數的功能:就是在Map中尋找HandlerMethod方法。Map中保存的是<url,HandlerMethod>
,Map中的內容如何來的呢:是在容器初始化時會建立所有url和controller的對應關係,保存到Map
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
chain.addInterceptors(getAdaptedInterceptors());
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
其中,private final List<MappedInterceptor> mappedInterceptors =
中保存的是我們項目配置文件配置的攔截器。
new ArrayList<MappedInterceptor>();
分析2:找到與用於處理request的handler相匹配的HandlerAdapter
DispatcherServlet.java
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
該getHandlerAdapter函數的功能爲:判斷private List<HandlerAdapter> handlerAdapters;
中哪個Adapter能支持這個handler。或者說,這個handler應該與哪個Adapter進行搭檔才能正常工作。
從Debug的情況來看,如果我們採用的是@RequestMapping註解形式,則獲取到的是HandlerAdapter 是RequestMappingHandlerAdapter類的一個實例。
以下就是RequestMappingHandlerAdapter的support方法的實現,即只要此時的handler爲HandlerMethod的實例,就是支持的。
AbstractHandlerMethodAdapter.java
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
RequestMappingHandlerAdapter
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
分析3:執行所有註冊攔截器的preHandler方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;//interceptorIndex標示着攔截器數組中下標小於等於interceptorIndex的攔截器已經被成功執行。
}
}
return true;
}
該函數的功能爲:調用所有註冊攔截器的preHandle方法,如果preHandle方法的返回結果爲true,則會繼續執行下面的程序。如果preHandler方法返回false,則調用triggerAfterCompletion方法。該方法的代碼如下:
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
從代碼中可以看到:triggerAfterCompletion方法它會調用所有已經成功執行的攔截器的afterCompletion方法,而且是反序調用的過程。
以上可以得到的結論爲:
1)只有所有註冊的攔截器都執行成功,即都返回true,則doDispathcer中的代碼纔會繼續執行。
2)如果第i個攔截器返回false,則會觸發triggerAfterCompletion方法來反序執行剛剛所有已經成功執行的攔截器的afterCompletion方法。並返回false從而使得doDispatcher中的代碼就不會往下執行了。
看到這裏,我們也就明白了攔截器的作用。
分析4:倒序執行所有註冊攔截器的postHandler方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
該函數的功能:反序執行所有註冊的攔截器的postHandler方法,比較簡單哈。
小結
就這樣我們稍微理清了下doDispatch這個方法的基本思路,有很多細節,博文中並沒有關注,如果你有興趣,可以仔細研究。
========================漂亮的分割線========================
博文的以上部分可以看作是SpringMVC用於處理Http請求的運行主線的源碼分析。而沒有分析初始化主線。在看了這篇博文之後(http://downpour.iteye.com/blog/1341459),感覺對SpringMVC的初始化主線又多了一份瞭解。
總結如下:
1、基於框架所編寫的應用程序的構成三要素。
a)入口程序DispatcherServlet,在web.xml文件中定義。
b)核心配置文件,[servlet-name]-servlet.xml文件。裏面定義了相關組件。
c)控制邏輯,Controller。
2、框架的具體實現。
有兩條主線。
a)初始化主線 -- 負責對SpringMVC的運行要素進行初始化。
b)用於處理http請求的運行主線 -- 負責對SpringMVC中的組件進行邏輯調度完成對Http請求的處理。
這兩條主線的劃分是根據servlet中的init方法和service方法來的,這兩個方法的運行時間和觸發條件截然不同。其中,init方法在整個系統啓動時運行,且只運行一次。因此,在init方法中我們往往會對整個應用程序進行初始化操作。而service方法在整個系統運行的過程中一直處於監聽模式,偵聽並處理所有的web請求。
SpringMVC的整個運行體系,是由DispatcherServlet、組件和容器這三者共同構成的。 既然是三個元素之間的關係表述,我們必須以兩兩關係的形式進行歸納:
DispatcherServlet - 容器 —— DispatcherServlet負責對容器進行初始化,初始化的依據是核心配置文件
容器 - 組件 —— 容器對組件進行全局管理
DispatcherServlet - 組件 —— DispatcherServlet對組件進行邏輯調用
2.1)初始化主線。
首先要明確3個觀點。
a)初始化主線的驅動方法:init().
b) 初始化主線的執行次序(根據DispatcherServlet的繼承結構而來):HttpServletBean–>FrameworkServlet–>DispatherServlet.
c) 初始化主線的操作對象:Spring容器(WebApplicatonContext)以及組件.
(配圖)
2.2)用於處理http請求的運行主線。
(配圖)