以下源碼版本(4.2.0.RELEASE)
dispacherServlet是servlet的實作類,是spring MVC的前端轉發器,是spring MVC的核心。
那麼它做了哪些事呢?
它主要做了兩件事:
NO1:
看如下源碼:
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
//初始化分段上傳解析器(成對檔案上傳的解析和封裝工作),沒有預設的實作
initMultipartResolver(context);
//初始化地域解析器,預設實作是AcceptHeaderLocaleResolver
initLocaleResolver(context);
//初始化主題解析器,預設實作是FixedThemeResolver
initThemeResolver(context);
//初始化處理器映射,這是個集合, 預設實作是BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping
initHandlerMappings(context);
//初始化處理器擴充卡,這是個集合,預設實作是HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter
initHandlerAdapters(context);
//初始化處理器異常解析器,這是個集合,預設實作是AnnotationMethodHandlerExceptionResolver,ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver
initHandlerExceptionResolvers(context);
//初始化請求到視圖名解析器,預設實作是DefaultRequestToViewNameTranslator
initRequestToViewNameTranslator(context);
//初始化視圖解析器,這是個集合,預設實作是InternalResourceViewResolver
initViewResolvers(context);
}
NO2:
每次請求都會調用它的doService方法,在doService方法中調用它的doDispatch方法。
doService方法可看代碼中的兩處注釋:
重點在于調用它的doDispatch方法:
doDispatch(request, response);
首先我們來看方法doDispatch的注釋:
可以簡單了解成:所有的請求都将在這個方法裡映射到指定的action的指定的方法(前提:請求路徑正确)。
我們來一步一步解析這個方法:
以下,為
doDispatch方法的源碼:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// processedRequest是經過checkMultipart方法處理過的request請求
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);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
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;
}
// Actually invoke the handler.
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);
}
}
}
}
第一行建立的變量processedRequest 會在
後面某一行(在doDispatch方法中,如下:)
processedRequest = checkMultipart(request);
中被方法處理加工,checkMultipart方法也是dispacherServlet類中的一個方法,源碼如下:
那麼這個方法的作用是什麼呢?
關鍵是下面這一句:
this.multipartResolver != null && this.multipartResolver.isMultipart(request)
這一句代碼做了如下兩個判斷:
1.dispatcherServlet中初始化後的multipartResolver是否為空(配置檔案中是否配置,初始化dispatcherServlet時沒有預設執行個體);
2.multipartResolver的方法isMultipart的作用是判斷本次請求是否為檔案上傳。
如下為isMultipart的源碼:
通過注釋,可簡單了解為:該方法通常以檢查content-type是否為multipart/form-data的方式判斷本次請求是否為檔案上傳,但實際功能需要看具體解析器對該方法的實作細節。
checkMultipart方法大緻如此,再具體一些的内容在這裡我就不贅述了,有興趣的朋友可以自己看源碼。
(多嘴一句:若想使用multipartResolver不要忘了增加jar包支援:commons.fileupload,common.io).
---------------------------------------
方法doDispatch的第二行建立了變量mappedHandler ,
類型為HandlerExecutionChain ,通過檢視該類的源碼,可清楚其作用,如下:
可了解其為一個處理鍊,包含了所有的handler和攔截器。
以下三行代碼為doDispatch的核心:
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
通過注釋,可了解前一句的作用:找到指定的handler,
後一句:找到對應的擴充卡adapter,
第三句:在這個函數裡面會真正執行request請求相對于handler的方法(這隻是大概的代碼流程,真正的調用方法之前還有很多先前處理。)
以下是我debug斷點的顯示資料:
該方法時DispatcherServlet類中的方法getHandler,可以看到這裡會對所有handlerMapper進行周遊,後執行HandlerMappering的getHandler方法,
如下:為HandlerMappering的getHandler方法:
這個方法會傳回一個handler和所有的攔截器,組裝成了一個HandlerExecutionChain類。也就是在方法doDispatch第二行代碼裡定義的mappedHandler,
該方法的具體實作是在org.springframework.web.servlet.handler.AbstractHandlerMapping中,如下:
/**
* Look up a handler for the given request, falling back to the default
* handler if no specific one is found.
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
@Override
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);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
這裡的getHandlerInternal是個抽象方法,有具體的HandlerMapping來實作,擷取到的handler如果為空,則擷取預設配置的handler,若為string類型,則表示要去spring配置容器中去找這個bean,
該方法剩下的部分正如HandlerMappering的getHandler方法注釋所描述的:傳回一個handler和所有的攔截器(有興趣可深入了解)。
--------------------------
再來看doDispath方法裡的
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
它首先調用了dispatcherServlet裡的 getHandlerAdapter方法;看其源碼如下:
看其注釋:該方法會通過已确定映射的handler類來尋找滿足條件的adapter,(注意,若沒有找到,會直接報servletException異常)。
這個方法的核心是 方法supports,這是個抽象方法,不同的擴充卡會有不同的内部細節,如下分别為
SimpleControllerHandlerAdapter和SimpleServletHandlerAdapter的實作:
通過supports方法,dispatcherervlet類可以确定本次請求request映射的adapter.
------------------------
最後看
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
這裡的mv是一個ModelAndView類,ha是前面獲得的擴充卡adapter,
方法handler()是個抽象方法,具體實作細節依賴于擴充卡adapter的實作類,
但我門可看其注釋,了解該方法的作用,
源碼如下:
其注釋的意思是是:使用提供的handler(前面确定的handler)來處理這個request請求。
以下,已實作類SimpleControllerHandlerAdapter為例,
這裡會執行handlerRequest(該方法的實作細節依賴于不同的實作類,最後傳回一個ModelAndAndView。
以上,為我本次研讀dispatcherServlet類的所得。
可總結為,dispatcherServlet根據預設或配置的handlermapping和adapter,選擇不同的方式對請求request請求進行處理,最後傳回一個視圖ModeAndView。
(那麼傳回值為json是如何實作的?····問題越來越多了)
----------------------------------補充----------------------------
可以看出,關于
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
部分,闡述的比較模糊,或者說,基本沒什麼描述,雖然這部分是核心,
我試圖過闡述其實作細節,但這部分的實作細節根據不同的handlerMapping和不同的adpater而不同,
是以,我準備在其他章節對其進行分别闡述。
轉載于:https://www.cnblogs.com/zqsky/p/6184436.html