1.springMVC的基本配置,我们都知道当我们搭建springMVC时都会去在web.xml中编写DispatcherServlet的配置,如下:
<!-- springMvc的核心前端控制器DispatcherServlet -->
<servlet>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!-- 必须指定springmvc的初始化路径 参数为contextConfigLocation -->
<!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如springMvc-servlet.xml-->
<param-name>contextConfigLocation</param-name>
<!-- 此处为空会报错 Could not open ServletContext resource [/WEB-INF/springMvc-servlet.xml] -->
<!-- 如果配置了spring的ContextLoaderListener监听器会默认去找/WEB-INF/applicationContext.xml-->
<!-- spring是父容器,springmvc是子容器 -->
<!-- 此处作为spring的简单实现 ,必须在配置文件中指定扫描包让spring可以找到容器 -->
<param-value>classpath:springMvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 拦截路径 -->
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
那么DispatcherServlet到底是什么,做了些什么,让我们来一起探索
2.DispatcherServlet本质上可以说是一个Servlet,我们来看一下它的结构
我们都知道写一个Servlet都是继承HttpServlet,重写doGet和doPost方法,那HttpServeltBean又为我们做了什么呢,我们分析一下
我们这里先从源头分析DispatcherServlet说起,我们只截取部分核心的代码
1.首先加载DispatcherServlet.properties配置文件中的默认属性
private static final Properties defaultStrategies;
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
static {
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
2.请求调用doService方法在request中设置一些属性
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) + "]");
}
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);
}
}
}
}
3.核心方法 doDispatch,这里才是Dispatcher的核心逻辑
-
3.1 getHandler(request) 通过request中的@RequestMapping获取到 请求的路径交给handerMapping处理,返回HandlerExecutionChain 请求链对象 (交给请求处理器处理)
3.2 getHandlerAdapter(HandlerExecutionChain) 通过 HandlerExecutionChain找到对应的handlerDispatcher处理
(交给处理器适配器处理) 找到对应的handerDispather
3.3 handle(processedRequest, response, mappedHandler.getHandler());
handlerDispatcher处理请求
3.4 applyDefaultViewName(processedRequest, mv);
将request中的名称和modelAndView绑定到一块
getDefaultViewName(HttpServletRequest request) 将请求转换成视图名称
3.5 View resolveViewName(String viewName, Map<String, Object> model, Locale locale,HttpServletRequest request)
将给定的视图名称解析为View对象(要渲染)
3.6 render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)
渲染请求,返回到jspprotected 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); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. 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; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. 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); } } }
}
4.最后上一张流程图帮助大家理解springMvc的大致流程
根据上图可以更加清楚springMvc的流程
1、 用户发送请求至前端控制器DispatcherServlet
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
5、 执行处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、 ViewReslover解析后返回具体View
10、 DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户