在学习SpringMvc源码之前,我们可以先回忆一下,我们觉得SpringMvc到底帮我们做了什么,然后我们才来学习springMVc到底是怎么做的。
1.提供了更丰富自由的路由规则
2.不需要用户编写request中参数绑定到实体的成员变量的代码
3.有丰富的参数绑定方式,例如路径的值可以绑定到参数中
4.不需要自己编写响应处理的代码,直接返回实体,框架就会帮我们处理成对应的响应
5.可以更方便的利用spring的特性
这次我们学习SpringMVC的处理流程,首先我们要知道一个请求过来,进入到servlet容器,会根据请求路径路由到相应的servlet处理器,并调用doService方法,而SpringMVC实现了一个特别的servlet.这个特别的servlet就是DispatcherServlet。DispatcherServlet的映射路径会配置成"/",所以这个servlet会接收所有请求。
那么我们首先来看一下这个DispacherServlet的doService方法。
@Override
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) + "]");
}
// 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<String, Object>();
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());
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);
}
}
}
}
可以看到,这段代码有很大一部分代码是给request设置一些属性,例如 webApplicationContext、localeResolve、themeResolver等等,
这些属性应该是便于以后处理使用。
然后就是调用doDispatch方法,处理请求。
最后还有一些异步请求的处理,这部分只能留到讲解异步请求的时候解释。
接着来看doDispatch方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//根据请求获取WebAsyncdManager,这类是跟异步处理有关
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
//这个类用于存储了Model跟View的信息
ModelAndView mv = null;
Exception dispatchException = null;
try {
//这个处理跟文件上传有关,如果请求中包含文件上传,会返回一个封装过的HttpServletRequest
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//根据请求获取处理调用链,这个链包含了具体handler和拦截器。
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
//如果找不到处理器就直接返回
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//根据处理器找到对应的适配器,因为有多种处理器,这里spring使用了适配器模式,使得调用统一。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
//如果是get请求或head请求,则根据请求调用handlerAdapter的getLastModified方法,如果已是最新的响应则直接返回。
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.
//处理请求,并返回modelAndView对象
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);
}
}
}
}
这里总结一下springMVC处理请求的逻辑算法大概有以下步骤:
1.检查是否有文件上传,并返回HttpServletRequest
2.根据请求获取处理调用链,这个链封装了具体handler和拦截器。
3.根据处理器找到对应的适配器,因为有多种处理器,这里spring使用了适配器模式,使得调用统一。
4.如果是get请求或head请求,则根据请求调用handlerAdapter的getLastModified方法,如果已是最新的响应则直接返回。
5.调用拦截器的预处理方法
6.处理请求,并返回modelAndView对象
7.如果是异步处理则返回到servlet容器
8.调用拦截器的后处理方法
9.处理响应
10.最后,有一个异步相关的处理和如果是含有文件上传需要清理资源 。
接着我们来看一下,getHandler方法,这一步是根据请求获取处理调用链。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//成员变量List<HandlerMapping> handlerMappings
//遍历handlerMappings
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
//调用HandlerMapping.getHandler方法,获取调用链。
HandlerExecutionChain handler = hm.getHandler(request);
//如果hanlder不为空,返回handler,为空,继续遍历,直到所有HandlerMapping都被遍历为止
if (handler != null) {
return handler;
}
}
//没有找到对应的hanlder直接返回
return null;
}
这里逻辑很简单,但涉及了一个组件,就是HandlerMapping。
public interface HandlerMapping{
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
这个接口就只定义了一个方法,就是根据请求获取HandlerExecutionChain,也就是这个接口定义了路由的规则。具体的规则都定义在了这个接口的实现类中,因为有许多实现类,所以提供了丰富的路由规则。
后面会更深入的讨论这个接口的实现类。
继续看一下getHandlerAdapter,即根据处理器找到对应的适配器这一步
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//List<HandlerAdapter> handlerAdapters
//遍历handlerAdapters
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
//调用HandlerAdapter.supports接口,如果支持则返回
if (ha.supports(handler)) {
return ha;
}
}
//如果没找到则抛出异常
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
这里的处理逻辑跟上面根据请求获取处理调用链的逻辑差不多,都是遍历所有现有的HandlerAdapter,直到找到适合的HandlerAdapter返回。
而这里就涉及了另一个组件HandlerAdapter。
public interface HandlerAdapter {
//返回是否支持调用handler
boolean supports(Object handler);
//执行hanler,并返回ModelAndView
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
//获取请求的最后修改时间
long getLastModified(HttpServletRequest request, Object handler);
}
这个组件的实现类的handle方法,主要做这3件事
第一、把request转换成参数
第二、调用具体的handler进行请求处理
第三、有部分实现还直接处理的响应
后面会更深入的讨论这个接口的实现类。
总结:
springMvc处理请求的流程其实非常简单,无非就是先根据请求找到对应的handler,然后再找到对应的handlerAdapter,然后就处理请求,但其实有很多处理细节,这些留在后面再做解释。