首先從入口開始:org.springframework.web.servlet.DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
/** Throw a NoHandlerFoundException if no Handler was found to process this request? *.*/
private boolean throwExceptionIfNoHandlerFound = false;
/** Perform cleanup of request attributes after include request?. */
private boolean cleanupAfterInclude = true;
/** MultipartResolver used by this servlet. */
@Nullable
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet. */
@Nullable
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet. */
@Nullable
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet. */
@Nullable
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet. */
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet. */
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
/** FlashMapManager used by this servlet. */
@Nullable
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet. */
@Nullable
private List<ViewResolver> viewResolvers;
public DispatcherServlet() {
super();
setDispatchOptionsRequest(true);
}
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* 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) {
/*
*從ApplicationContext中得到MultipartResolver.class類型
*且名為multipartResolver的Bean伐坏,如:
*1纫塌,CommonsMultipartResolver
*2羽历,StandardServletMultipartResolver
*/
initMultipartResolver(context);
/*
*從ApplicationContext中得到LocaleResolver.class類型
*且名為localeResolver的Bean稽犁; 如果沒有得到,則使用
*DispatcherServlet.properties文件中默認(rèn)配置的對(duì)象
*/
initLocaleResolver(context);
/*
*從ApplicationContext中得到ThemeResolver.class類型
*且名為themeResolver的Bean陨帆; 如果沒有得到曲秉,則使用
*DispatcherServlet.properties文件中默認(rèn)配置的對(duì)象
*/
initThemeResolver(context);
/*
*如果detectAllHandlerMappings屬性設(shè)置為ture(檢測(cè)所有handlerMapping),
*則從ApplicationContext中得到所有HandlerMapping.class類的Bean疲牵;
*否則使用得到名為handlerMapping類型為HandlerMapping.class的Bean;
*---------------------
*例如以下常見的:
*1,RequestMappingHandlerMapping
*2,SimpleUrlHandlerMapping
*3,ControllerEndpointHandlerMapping
*4,WebMvcEndpointHandlerMapping
*5,BeanNameUrlHandlerMapping
*6,RouterFunctionMapping
*7,PropertySourcedRequestMappingHandlerMapping
*8,WelcomePageHandlerMapping
*9,CompositeHandlerMapping
*/
initHandlerMappings(context);
/*
*如果detectAllHandlerAdapters屬性設(shè)置為ture(檢測(cè)所有handlerAdapter)岸浑,
*則從ApplicationContext中得到所有HandlerAdapter.class類的Bean;
*否則使用得到名為handlerAdapter類型為HandlerAdapter.class的Bean;
*---------------------
*例如以下常見的:
*1,SimpleServletHandlerAdapter
*2,SimpleControllerHandlerAdapter
*3,HttpRequestHandlerAdapter
*4,HandlerFunctionAdapter
*5,RequestMappingHandlerAdapter
*6,CompositeHandlerAdapter
*/
initHandlerAdapters(context);
/*
*如果detectAllHandlerExceptionResolvers屬性設(shè)置為ture(檢測(cè)所有HandlerExceptionResolver)瑰步,
*則從ApplicationContext中得到所有HandlerExceptionResolver.class類的Bean;
*否則使用得到名為handlerExceptionResolver類型為HandlerExceptionResolver.class的Bean;
*---------------------
*例如以下常見的:
*1,SimpleMappingExceptionResolver
*2,ResponseStatusExceptionResolver
*3,DefaultHandlerExceptionResolver
*4,ExceptionHandlerExceptionResolver
*5,DefaultErrorAttributes
*6,HandlerExceptionResolverComposite
*7,CompositeHandlerExceptionResolver
*/
initHandlerExceptionResolvers(context);
/*
*從ApplicationContext中得到RequestToViewNameTranslator.class類型
*且名為viewNameTranslator的Bean璧眠; 如果沒有得到缩焦,則使用
*DispatcherServlet.properties文件中默認(rèn)配置的對(duì)象
*/
initRequestToViewNameTranslator(context);
/*
*如果detectAllViewResolvers屬性設(shè)置為ture(檢測(cè)所有l(wèi)ViewResolver),
*則從ApplicationContext中得到所有ViewResolver.class類的Bean责静;
*否則使用得到名為viewResolver類型為ViewResolver.class的Bean;
*---------------------
*例如以下常見的:
*1,InternalResourceViewResolver
*2,ResourceBundleViewResolver
*3,MustacheViewResolver
*4,XsltViewResolver
*5,TilesViewResolver
*6,XmlViewResolver
*7,BeanNameViewResolver
*8,ContentNegotiatingViewResolver
*9,GroovyMarkupViewResolver
*10,FreeMarkerViewResolver
*11,ViewResolverComposite
*/
initViewResolvers(context);
/*
*從ApplicationContext中得到FlashMapManager.class類型
*且名為flashMapManager的Bean袁滥; 如果沒有得到,則使用
*DispatcherServlet.properties文件中默認(rèn)配置的對(duì)象
*/
initFlashMapManager(context);
}
/**
* 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 {
logRequest(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<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
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());
if (this.flashMapManager != null) {
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);
}
}
}
}
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
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);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == 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 (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;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", 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);
}
}
}
}
}
小結(jié):對(duì)請(qǐng)求處理的大體過程
檢查是不是文件上傳(Multipart)灾螃,如果是則對(duì)Request進(jìn)行解析返回包裝后的HttpServletRequest
-
根據(jù)HttpServletRequest得到匹配的HandlerMapping题翻,并返回HandlerMapping的getHandler方法返回的結(jié)果HandlerExecutionChain
如果返回的HandlerExecutionChain為null,當(dāng)throwExceptionIfNoHandlerFound屬性為ture(默認(rèn)為false)時(shí)則拋出NoHandlerFoundException異常腰鬼,否則直接響應(yīng)404
-
使用HandlerExecutionChain的getHandler()方法的返回結(jié)果作為參數(shù)來查找匹配的HandlerAdapter
HandlerExecutionChain的getHandler()方法的返回結(jié)果(Handler)作為參數(shù)調(diào)用每個(gè)HandlerAdapter的supports方法嵌赠,如果找到則返回該HandlerAdapter,否則拋出ServletException異常
使用Request熄赡,Response以及Handler作為參數(shù)執(zhí)行HandlerAdapter的handle方法姜挺,并得到返回值ModelAndView
-
給ModelAndView設(shè)值默認(rèn)的viewName值(如果返回的ModelAndView沒有設(shè)置viewName)
如果viewNameTranslator不為null,則以HttpServletRequest作為參數(shù)執(zhí)行其getViewName方法得到默認(rèn)的名稱(也可能為null)
-
捕獲上面過程中執(zhí)行得到的Exception(沒發(fā)生異常則為null),并結(jié)合HttpServletRequest彼硫、HttpServletResponse炊豪、HandlerExecutionChain、ModelAndView作為參數(shù)執(zhí)行processDispatchResult方法
1)如果Exception不為空拧篮,且不是ModelAndViewDefiningException異常词渤,則執(zhí)行processHandlerException方法返回ModelAndView;迭代執(zhí)行每個(gè)HandlerExceptionResolver的resolveException方法串绩,如果中途返回的ModelAndView不為空則返回缺虐,如果最終得到的ModelAndView為null
2)如果ModelAndView中的viewName不為空則遍歷所有ViewResolver并執(zhí)行resolveViewName方法的到View實(shí)例,如果最終得到的為null赏参,則拋出ServletException異常志笼; 如果viewName為空沿盅,則直接從ModelAndView對(duì)象中返回View實(shí)例,如果為空依然拋出異常纫溃。
3)執(zhí)行View的render訪問完成視圖的渲染
清除Multipart