Spring MVC的核心控制器为Servlet,所有访问服务端的请求都将由servlet拦截接受,并进行相应处理最终进行返回。下面我们来看看它究竟是怎么做的。
SpringMVC中的Servlet一共有三个层次,分别是HttpServletBean、FrameworkServlet和 DispatcherServlet。
HttpServletBean直接继承自java的HttpServlet,其作用是将Servlet中配置的参数设置到相应的属性;FrameworkServlet初始化WebApplicationContext,而DispatchServlet初始化SpringMVC九大组件。可以具体看代码:
// 初始化servlet九大组件
protected void initStrategies(ApplicationContext context) {
// 初始化文件上传组件,将普通的request包装成MultipartHttpServletRequest,后者可以直接通过getFile获取文件
initMultipartResolver(context);
// 初始化local解析器(EN-US;ZH-CN)
initLocaleResolver(context);
// 初始化主题解析器
initThemeResolver(context);
// 初始化HandlerMapping
initHandlerMappings(context);
// 初始化HandlerAdapters
initHandlerAdapters(context);
// 初始化全局异常处理类
initHandlerExceptionResolvers(context);
// 初始化RequestToViewNameTranslator,从request中获取ViewName
initRequestToViewNameTranslator(context);
// 初始化视图解析器,将String类型视图名和local解析为View类型视图
initViewResolvers(context);
// 初始化FlashMap(FlashMap用于在redirect中传递参数)
initFlashMapManager(context);
}
而http请求被servlet拦截后都将调用doService方法以调度到具体的handlerMapping中进行处理:
/**
* 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 {
if (logger.isDebugEnabled()) {
// 获取请求来源uri
String requestUri = urlPathHelper.getRequestUri(request);
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + requestUri + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
// 将request请求中的各个属性参数放入一个快照Map中
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
logger.debug("Taking snapshot of request attributes before include");
attributesSnapshot = new HashMap<String, Object>();
// 获取该请求所有参数
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
// cleanupAfterInclude默认为true,若为servlet参数则放入Map中
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
// 将mvc的webApplicationContext、主题解析器、主题、local解析器放入请求参数中
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,然后删除过期的FlashMap,并选取一个适合当前请求的FlashMap返回
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
// 若找到合适的FlashMap,将其转换成一个不可变Map(不支持任何修改操作 put,remove,clear都将报错),放入请求参数中
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 {
// 将请求调度至handlerMapping处理
doDispatch(request, response);
}
finally {
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
dodispatch方法将真正将请求定位至处理方法中,并在其中加入拦截器的处理、异常处理、返回视图的构建:
/**
* 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主要用来管理异步请求的处理,当业务逻辑复杂(或者其他原因),为了避免请求线程阻塞,需要委托给另一个线程时使用
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 判断请求是否为文件上传类型,若是则返回MultipartRequest,若否则返回原request
processedRequest = checkMultipart(request);
// 判断是否为MultipartRequest标识,若上一句 返回不是原request则证明是MultipartRequest
multipartRequestParsed = processedRequest != request;
// Determine handler for the current request.
// handlerMappings中包含了所有注册在IOC容器中的Handler
// ①遍历handlerMappings列表,找到与request中请求名称相同的handler,通过ApplicationContext.getBean方法获取handlerBean
// ②通过获取到的handlerBean再获取可将handler拦截的拦截器链
mappedHandler = getHandler(processedRequest);
// 若未找到对应的handler则抛出异常或返回http-404
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 通过handler找到对应的HandlerAdapter
// HandlerAdapter为处理器适配器,作用为根据请求去定位请求的具体处理方法是哪个
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
// 若此http请求为get方法,则获取浏览器端上送的最后修改时间,若最后修改时间与服务器端一致,则说明无变化
// 无变化则方法直接返回,浏览器可继续用上次get方法获取到的数据缓存即可
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 此处依次遍历执行拦截器链的preHandler方法,若其中有一个return false或者抛出异常则执行拦截器链的afterCompletion方法,最后return此次请求
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 通过handlerAdapter定位到具体的处理方法处理请求
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
// 获取ModelAndView
applyDefaultViewName(request, mv);
// 此处反序遍历执行拦截器链的postHandler方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 处理请求的返回信息:若有异常则返回异常视图;若返回正常则调用render方法返回正常视图
// 并反序执行拦截器链的afterCompletion方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 若抛出异常也需反序执行拦截器链的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
// 若抛出Error级异常也需反序执行拦截器链的afterCompletion方法
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
// 若为文件上传请求,最后还需清理掉上传文件的缓存信息
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}