4. Spring MVC 源码深度剖析

4.1 前端控制器 DispatcherServlet 继承结构

4.2 重要时机点分析

1. Handler方法的执行时机

观看调用栈:

doDispathch方法中的1064行代码完成handler方法的调用

2. ⻚面渲染时机

打断点并观察调用栈

SpringMVC处理请求的流程即为 org.springframework.web.servlet.DispatcherServlet#doDispatch方法的执行过程,其中步骤 2、3、4、5是核心步骤

  1. 调用getHandler()获取到能够处理当前请求的执行链 HandlerExecutionChain(Handler+拦截器)

  2. 调用getHandlerAdapter();获取能够执行1)中Handler的适配器 但是如何去getHandlerAdapter的?后面进行分析

  3. 适配器调用Handler执行ha.handle(总会返回一个ModelAndView对象)

  4. 调用processDispatchResult()方法完成视图渲染跳转

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 {
// 1 检查是否是文件上传的请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

// Determine handler for the current request.
// 2 取得处理当前请求的Controller,这里也称为Handler,即处理器
// 这里并不是直接返回 Controller,而是返回 HandlerExecutionChain 请求处理链对象
// 该对象封装了Handler和Interceptor
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 如果 handler 为空,则返回404
noHandlerFound(processedRequest, response);
return;
}

// Determine handler adapter for the current request.
// 3 获取处理请求的处理器适配器 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.
// 处理 last-modified 请求头
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.
// 4 实际处理器处理请求,返回结果视图对象
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);
}
// 5 跳转⻚面,渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception ex) {
//最终会调用HandlerInterceptor的afterCompletion 方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
} catch (Throwable err) {
//最终会调用HandlerInterceptor的afterCompletion 方法
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);
}
}
}
}

4.3 核心步骤getHandler方法剖析

遍历两个HandlerMapping,试图获取能够处理当前请求的执行链

4.4 核心步骤getHandlerAdapter方法剖析

遍历各个HandlerAdapter,看哪个Adapter支持处理当前Handler

默认配置 DispatcherServlet.properties

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

4.5 核心步骤ha.handle方法剖析

  • 入口

4.6 核心步骤processDispatchResult方法剖析

4.7 SpringMVC九大组件初始化

  1. 在DispatcherServlet中定义了九个属性,每一个属性都对应一种组件
/** 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. */
// flash属性管理组件
@Nullable
private FlashMapManager flashMapManager;

/** List of ViewResolvers used by this servlet. */
// 视图解析器
@Nullable
private List<ViewResolver> viewResolvers;

九大组件都是定义了接口,接口其实就是定义了该组件的规范,比如ViewResolver、HandlerAdapter 等都是接口。

  1. 九大组件的初始化时机
  • DispatcherServlet中的onRefresh(),该方法中初始化了九大组件

  • initStrategies方法

  • 观察其中的一个组件initHandlerMappings(context)

  • 如果按照类型和按照固定id从ioc容器中找不到对应组件,则会按照默认策略进行注册初始化,默 认策略在DispatcherServlet.properties文件中配置

  • DispatcherServlet.properties

  • 注意:多部件解析器的初始化必须按照id注册对象(multipartResolver)