首页 技术 正文
技术 2022年11月9日
0 收藏 764 点赞 3,549 浏览 5875 个字

一、源码分析前还是需要一张流程图作为指导,如下:

二、简单介绍以及源码定位

DispatcherServlet其实就是一个HttpServlet,他是HttpServlet的子类,所以它和普通的HttpServlet在web.xml里同样的配置。

这个Servlet的doPost和doGet方法的实现是DispatcherServlet的父类FrameworkServlet中实现的,两个方法里都是调用processRequest方法。processRequest的实现是在FrameworkServlet中,此方法中最主要的操作就是调用doService方法。

doService方法的最终实现是在DispatcherServlet中,这样所有的Http请求(GET、POST、PUT和DELETE等)的最终操作就DispatcherServlet中实现了。

DispatcherServlet中doService的实现如下,对Request设置了一些全局属性,最终接下来的操作是在doDispatcher函数中实现了。

[java] view plain copy
//获取请求,设置一些request的参数,然后分发给doDispatch
@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("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
} // Make framework objects available to handlers and view objects.
/* 设置web应用上下文**/
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));
}
//Flash attributes 在对请求的重定向生效之前被临时存储(通常是在session)中,并且在重定向之后被立即移除
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
//FlashMap 被用来管理 flash attributes 而 FlashMapManager 则被用来存储,获取和管理 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);
}
}
}
}

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 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;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
}
}
}
}

三、通过阅读源码总结分析流程如下:

1. web应用服务器接收到一个新请求是,读取web.xml中的配置,如果匹配DispatcherServlet的请求映射路径,web容器将该请求转发给DispatcherServlet进行处理

2. DispatcherServlet接收到请求后,执行doDispatch方法,此方法遍历DispatcherServlet中的HandlerMapping(处理器映射器)集合,根据请求的HttpServletRequest信息通过HandlerMapping对象方法找到HandlerExecutionChain(执行链,内含拦截器和处理器)。

3. DispatcherServlet继续执行doDispatch方法,根据得到的HandlerExecutionChain(执行链)中的handler遍历自己的HandlerAdapter(处理器适配器)集合,找到支持这个Handler的HandlerAdapter并返回。

4.继续doDispatch方法,把HandlerExecutionChain(执行链)内部的那些前置拦截器逻辑都执行完,然后再再通过得到的HandlerAdapter执行HandlerExecutionChain内部的处理器,会返回一个ModelAndView包含了视图逻辑名和模型数据信息

5.调用执行链的方法,执行拦截器的后置拦截器

6. ModelAndView中包含的是“逻辑视图名”,而非真正的视图对象,DispatcherServlet借助ViewResolver完成逻辑视图名到真实视图名对象的解析工作

7. 当得到真实的视图对象View后,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染

8. 最终客户端得到HTML页面什么的

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,488
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,903
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,737
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,489
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,128
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,290