你要知道的SpringMVC DispatcherServlet执行流程及源码分析都在这里
转载请注明出处 http://blog.youkuaiyun.com/u014205968/article/details/78184424
本系列文章主要根据源码讲解SpringMVC
的启动过程,以及相关重要组件的源码分析。阅读此系列文章需要具备Spring
以及SpringMVC
相关知识。本文将分以下几篇文章进行讲解,读者可按需查阅。
- SpringMVC 启动流程及相关源码分析
- SpringMVC DispatcherServlet执行流程及源码分析
- SpringMVC HandlerMapping源码分析
- SpringMVC HandlerAdapter源码分析
DispatcherServlet执行流程及相关源码分析
在前一篇文章SpringMVC 启动流程及相关源码分析中,详细探讨了Spring MVC
在Web容器
中部署后的启动过程,以及相关源码分析,同时也讨论了DispatcherServlet类
的初始化创建过程,相关内容在此不再赘述,如有需求可查阅。
本文主要讲解DispatcherServlet类
获取用户请求到响应的全过程,并针对相关源码进行分析。对于基本的MVC架构
本文不再进行讲解,有需要的读者可自行查阅。
首先,让我们站在Spring MVC
的四大组件:DispatcherServlet
、HandlerMapping
、HandlerAdapter
以及ViewResolver
的角度来看一下Spring MVC
对用户请求的处理过程,有如下时序图:
具体处理过程如下:
- 1、用户请求发送至
DispatcherServlet类
进行处理。 - 2、
DispatcherServlet类
遍历所有配置的HandlerMapping类
请求查找Handler
。 - 3、
HandlerMapping类
根据request请求
的URL
等信息查找能够进行处理的Handler
,以及相关拦截器interceptor
并构造HandlerExecutionChain
。 - 4、
HandlerMapping类
将构造的HandlerExecutionChain类
的对象返回给前端控制器DispatcherServlet类
。 - 5、前端控制器拿着上一步的
Handler
遍历所有配置的HandlerAdapter类
请求执行Handler
。 - 6、
HandlerAdapter类
执行相关Handler
并获取ModelAndView类
的对象。 - 7、
HandlerAdapter类
将上一步Handler
执行结果的ModelAndView 类
的对象返回给前端控制器。 - 8、
DispatcherServlet类
遍历所有配置的ViewResolver类
请求进行视图解析。 - 9、
ViewResolver类
进行视图解析并获取View
对象。 - 10、
ViewResolver类
向前端控制器返回上一步骤的View
对象。 - 11、
DispatcherServlet类
进行视图View
的渲染,填充Model
。 - 12、
DispatcherServlet类
向用户返回响应。
通过时序图和上面的讲解不难发现,整个Spring MVC
对于用户请求的响应和处理都是以DispatcherServlet类
为核心,其他三大组件均与前端控制器进行交互,三大组件之间没有交互并且互相解耦,因此,三大组件可以替换不同的实现而互相没有任何影响,提高了整个架构的稳定性并且降低了耦合度。接下来会按照上述的响应过程逐一进行讲解。
DispatcherServlet类
本质上依旧是一个Servlet
并且其父类实现了Servlet接口
,我们知道,Servlet
执行Service()
方法对用户请求进行响应,根据前一篇文章的分析方法可以得到人如下的调用逻辑图:
从上图的源码调用逻辑可以看出,HttpServlet抽象类
实现了Servlet接口
的service(ServletRequest, ServletResponse)
的方法,因此,用户请求的第一执行方法为该方法,该方法紧接着直接调用了service(HttpServletRequest, HttpServletResponse)
方法,其子类FrameworkServlet抽象类
重写了该方法,因为多态的特性最终是调用了FrameworkServlet抽象类
的service(HttpServletRequest, HttpServletResponse)
方法,FrameworkServlet抽象类
同样也重写了doHead()
、doPost()
、doPut()
、doDelete()
、doOptions()
、doTrace()
方法,service(ServletRequest, ServletResponse)
方法根据请求类型的不同分别调用上述方法,上述六个方法都调用了processRequest()
方法,而该方法最终调用了DispatcherServlet类
的doService()
方法。通过层层分析,我们找到了最终要调用的处理用户请求的方法,doService()
之前的方法调用都比较简单,这里不再逐一来查看源码,有兴趣的读者可以自行查阅。
查看doService()
的源码如下:
/**
* 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()) {
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.
/*
将当前Servlet的子IoC容器放入request请求中
由此,我们可以访问到当前IoC子容器以及根IoC容器中的Bean
*/
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);
}
fina