Spring MVC 执行流程
对于 Spring MVC 的流程一直很感兴趣,所以画了个上面的流程图来梳理过程,下面用文字解释
一 映射地址是否存在
图中的第 2 步。我们在请求网页的时候,不仅仅是为了请求 Servlet,有时候需要请求一些静态资源,如 jQuery,CSS,图片等。因为SpringMVC 的 DispatchServlet 会处理所有的请求,那么对应的静态资源没有 Servlet 映射地址。该怎么办,通常在配置文件加:
<mvc:default-servlet-handler/>
来交给在面对找不到的映射地址时,就交给默认 Servlet 处理器来处理,获取静态资源。如果这都还找不到的话,只能返回 404 了。
二 处理器映射器
图中第 3 步,将请求映射到对应的处理程序,以及用于预处理和后处理的拦截器列表。充当着 url 和 Controller 之间映射关系配置的角色。最后返回了 HandleExecutionChain (包括了处理器对象和处理器拦截器)给 DispatchServlet。
HandleExecutionChain 源码的属性你可以看到一些熟悉的,包括拦截器等等
....
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
@Nullable
private HandlerInterceptor[] interceptors;
@Nullable
private List<HandlerInterceptor> interceptorList;
....
三 适配器
图中第 4 步。帮助 DispatcherServlet 调用映射对应请求的处理程序,而不管该处理程序实际是如何调用的。例如,调用带注释的 Controller 需要解析注释、参数封装,数据格式转换,数据验证等操作等。这是适配器模式的应用,通过扩展适配器可以对更多的类型处理器进行执行。
HandlerAdapter 的主要目的是 DispatcherServlet 不受这些细节的影响。
四 调用拦截器
第 5 步,在适配器调用实际的请求处理程序(目标方法)时,需要先调用内置或自定义拦截器的 preHandle()
方法,如果该方法的返回值为 false,那么则不会调用请求处理程序。直接返回,不在向下进行
五 执行目标方法
第 6 步,执行处理器 Handle,也就是执行我们映射地址对应的目标方法,并且返回一个 ModelAndView 对象
六 异常处理器
第 7 步,如果在执行目标方法的过程中出现了异常,就会交给异常解析器,要么打印异常信息,返回一个异常解析器生成的 ModelAndView 对象。或者如果自定义了异常解析器,也就会安装你自定义的逻辑来。不在向下执行。
其实好像这里的异常处理器不只是出现这里,还有其他地方等等。
七 postHandle 方法
第 8 步,执行内置拦截器或自定义的 postHandle()
方法。
八 视图解析器
第 9 步,视图解析器用来解析视图,并且返回一个 View。而且拦截器的 afterCompletion()
也在这里执行了。
ViewResolver 负责解析处理结果生成 View 对象,ViewResolver 首先根据逻辑视图名称解析成物理视图名称,也就是我们的页面地址,再生成 View 对象,返回。
九 渲染视图
第 10 步,把 View 对象进行渲染结果通过页面展示给用户。
其中 View 是 Spring MVC 封装的对象,它是一个接口,Spring MVC 还提供了很多视图类,例如 jspview、pdfview,jstlView、freemarkerView等等。
源码分析
对比上面的流程,我们看源码,第一站,在 DispatchServlet 的 Service 准备工作
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) + "]");
}
// /保存请求属性的快照,以备使用
// 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));
}
}
}
// /将框架对象放到 request,后面处理程序和视图对象可用。
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);
}
}
}
}
总览
在 DispatchServlet 的 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);
// 确定当前请求的处理程序。
// 用于获取包含处理器Handler和拦截器AdapterIntercepters的处理器执行链HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 确定当前请求的处理器适配器。
// 根据HandlerExecutionChain中的处理器Handler获取处理器适配器
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;
}
}
// 执行拦截器的 preHandle 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//通过处理器适配器 HandlerApapter 来调用处理器完成对请求的处理
// 实际调用处理程序。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
//// 执行拦截器的 postHandle 方法
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);
}
}
}
}
如何处理请求映射
经由 HandlerMapping 对象获取 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;
}
那么 hm.getHandle() 如何?
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 = obtainApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
经由 request 获取处理器,获取处理器 Handler 后,再获取拦截器,最后组成 HandlerExecutionChain。
获取适配器
根据 Handler 获取 HandlerAdapter。
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 +
"]: Does your handler implement a supported interface like Controller?");
}
调用目标方法
使用处理器完成对请求的处理
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((Servlet) handler).service(request, response);
return null;
}
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
// 继续调用 service 判断请求方法,并且调用对应的 doGet() 或 doPost() 等等
service(request, response);
}
service(HttpServletRequest req, HttpServletResponse resp)
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// 进一步执行请求的逻辑
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
......
}
}
渲染视图和解析视图名
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 处理程序是否返回一个要渲染的视图?
if (mv != null && !mv.wasCleared()) {
// 渲染视图和解析视图
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
//打印日志
......
}
if (mappedHandler != null) {
//调用拦截器的 afterCompletion 方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
继续 render 方法
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 确定请求的语言环境,并将其应用于响应。也就是国际化解析
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 我们需要解析视图名。
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
......
}
else {
// 不需要查找:ModelAndView对象包含实际的视图对象。
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// 委托视图对象进行渲染。
....
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
//渲染视图
view.render(mv.getModelInternal(), request, response);
}
......
}
以上只是个人理解,有错包含并指出哈。