下面是 SpringMVC 运行流程的分析图,包括了拦截器的调用过程,目标资源的处理以及异常处理。
在上面的流程图中有几个比较重要的组件,下面大概描述一下其对应的作用。
DispatcherServlet
:用于接收请求,响应结果。相当于转发器,中央处理器。用户请求到达DispatcherServlet
,它是整个流程控制中心,由它调用其它组件来处理用户的请求,DispatcherServlet
的存在降低了组件之间的耦合性。
HandlerMapping
:负责根据用户请求的URL
找到handler
路由处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
HandlerAdapter
:按照特定的规则帮助DispatcherServlet
去执行handler
。比如调用带注释的控制器需要解析注释等。
ViewResolver
:提供视图名称和实际视图之间的映射。ViewResolver
首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成View
视图对象,最后对View
进行渲染将处理结果通过页面展示给用户。
运行流程的执行通过DispatcherServlet
中的doDispatch(HttpServletRequest request, HttpServletResponse response)
方法进行统一的调用与管理。
PS:这里只能给大家提供一个调试代码的方法,其中有很多细节这里就不再一一描述了。
下面贴出 SpringMVC 4.3.16.RELEASE
版本中 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);
// 在getHandler方法中通过HandlerMapping获得HandlerExecutionChain对象
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获得HandlerAdapter对象
HandlerAdapter ha = 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 (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;
}
// 调用目标路由方法得到ModelAndView对象
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) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
/**
* 在processDispatchResult() 方法中首先会判断是否存在异常,然后完成试图的渲染,
* 并调用拦截器的afterCompletion()方法
*/
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()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
doDispatch(HttpServletRequest request, HttpServletResponse response)
方法调用了很多其他的方法来保证运行流程正确的执行,对于这些方法具体做了什么,需要你自己通过 DEBUG 的方式去了解。