DispatcherServlet是整个SpringMVC初始化和处理请求的重要类,作为一个servlet,拥有

public void init(ServletConfig config) throws ServletException;public ServletConfig getServletConfig();public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;public String getServletInfo();public void destroy();

  

这些基础方法和其他扩展方法。

init  service destroy 方法

<servlet><servlet-name>springMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]- servlet.xml,如spring-servlet.xml --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath*:config/spring-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这个类

--------------------------------

我们可以看到org.springframework.web.servlet.DispatcherServlet类继承了FrameworkServlet类

public class DispatcherServlet extends FrameworkServlet

org.springframework.web.servlet.FrameworkServlet类继承了HttpServletBean类 而HttpServletBean类又继承了HttpServlet类(该类属于servlet-api了)

public abstract class FrameworkServlet extends HttpServletBean
public abstract class HttpServletBean extends HttpServlet

 javax.servlet.http.HttpServlet类    org.springframework.web.servlet.HttpServletBean类  org.springframework.web.servlet.FrameworkServlet类

org.springframework.web.servlet.DispatcherServlet类

下面我们看servlet的处理请求的过程 重写的doGet doPost方法在FrameworkServlet当中

/*** Delegate GET requests to processRequest/doService.* <p>Will also be invoked by HttpServlet's default implementation of <code>doHead</code>,* with a <code>NoBodyResponse</code> that just captures the content length.* @see #doService* @see #doHead*/@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}

/*** Delegate POST requests to {@link #processRequest}.* @see #doService*/@Overrideprotected final void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}

他们都调用了processRequest(request,response)方法,该方法仍在FrameworkServlet当中

/*** Process this request, publishing an event regardless of the outcome.* <p>The actual event handling is performed by the abstract* {@link #doService} template method.*/protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {long startTime = System.currentTimeMillis();Throwable failureCause = null;// Expose current LocaleResolver and request as LocaleContext.LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);// Expose current RequestAttributes to current thread.RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes requestAttributes = null;if (previousRequestAttributes == null || previousRequestAttributes.getClass().equals(ServletRequestAttributes.class)) {requestAttributes = new ServletRequestAttributes(request);RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);}if (logger.isTraceEnabled()) {logger.trace("Bound request context to thread: " + request);}try {doService(request, response);}catch (ServletException ex) {failureCause = ex;throw ex;}catch (IOException ex) {failureCause = ex;throw ex;}catch (Throwable ex) {failureCause = ex;throw new NestedServletException("Request processing failed", ex);}finally {// Clear request attributes and reset thread-bound context.LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);if (requestAttributes != null) {RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);requestAttributes.requestCompleted();}if (logger.isTraceEnabled()) {logger.trace("Cleared thread-bound request context: " + request);}if (failureCause != null) {this.logger.debug("Could not complete request", failureCause);}else {this.logger.debug("Successfully completed request");}if (this.publishEvents) {// Whether or not we succeeded, publish an event.long processingTime = System.currentTimeMillis() - startTime;this.webApplicationContext.publishEvent(new ServletRequestHandledEvent(this,request.getRequestURI(), request.getRemoteAddr(),request.getMethod(), getServletConfig().getServletName(),WebUtils.getSessionId(request), getUsernameForRequest(request),processingTime, failureCause));}}}

对于该processRequest当中的其他方法暂时撇开不谈,看看其中的处理方法

doService(request,response)

/*** Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}* for the actual dispatching.*/@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) {String requestUri = urlPathHelper.getRequestUri(request);logger.debug("DispatcherServlet with name '" + getServletName() + "' 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.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();if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {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());try {doDispatch(request, response);}finally {// Restore the original attribute snapshot, in case of an include.if (attributesSnapshot != null) {restoreAttributesAfterInclude(request, attributesSnapshot);}}}

负责将初始化好的framework的context放置进request当中方便后续处理

// 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());

 

下面看doDispatch(request,reponse)方法,也是在DispatcherServlet类当中

/*** 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;int interceptorIndex = -1;try {ModelAndView mv;boolean errorView = false;try {processedRequest = checkMultipart(request);// Determine handler for the current request.mappedHandler = getHandler(processedRequest, false);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()) {String requestUri = urlPathHelper.getRequestUri(request);logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}// Apply preHandle methods of registered interceptors.HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();if (interceptors != null) {for (int i = 0; i < interceptors.length; i++) {HandlerInterceptor interceptor = interceptors[i];if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);return;}interceptorIndex = i;}}// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// Do we need view name translation?if (mv != null && !mv.hasView()) {mv.setViewName(getDefaultViewName(request));}// Apply postHandle methods of registered interceptors.if (interceptors != null) {for (int i = interceptors.length - 1; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);}}}catch (ModelAndViewDefiningException ex) {logger.debug("ModelAndViewDefiningException encountered", ex);mv = ex.getModelAndView();}catch (Exception ex) {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(processedRequest, response, handler, ex);errorView = (mv != null);}// Did the handler return a view to render?if (mv != null && !mv.wasCleared()) {render(mv, processedRequest, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}else {if (logger.isDebugEnabled()) {logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +"': assuming HandlerAdapter completed request handling");}}// Trigger after-completion for successful outcome.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);}catch (Exception ex) {// Trigger after-completion for thrown exception.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);throw ex;}catch (Error err) {ServletException ex = new NestedServletException("Handler processing failed", err);// Trigger after-completion for thrown exception.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);throw ex;}finally {// Clean up any resources used by a multipart request.if (processedRequest != request) {cleanupMultipart(processedRequest);}}}

下面分析上面的这个方法

HandlerExecutionChain mappedHandler = null;
.........
........
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);

/*** 返回request请求对应的 HandlerExecutionChain 对象. 按照顺序遍历所有的handler mapping* @param request current HTTP request* @param cache whether to cache the HandlerExecutionChain in a request attribute* @return the HandlerExecutionChain, or <code>null</code> if no handler could be found* @deprecated as of Spring 3.0.4, in favor of {@link #getHandler(javax.servlet.http.HttpServletRequest)},* with this method's cache attribute now effectively getting ignored*/@Deprecatedprotected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {return getHandler(request);}

真正执行遍历的方法,仍然在DispatcherServlet类当中

/*** Return the HandlerExecutionChain for this request.* <p>Tries all handler mappings in order.* @param request current HTTP request* @return the HandlerExecutionChain, or <code>null</code> if no handler could be found*/protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {for (HandlerMapping hm : this.handlerMappings) {if (logger.isTraceEnabled()) {logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");}HandlerExecutionChain handler = hm.getHandler(request);if (handler != null) {return handler;}}return null;}

  

我们看到HandlerExectionChain类是通过HandlerMapping类的gatHandler(HttpServletRequest request)方法创建的  HandlerMapping是个接口,三个常量,一个方法

package org.springframework.web.servlet;import javax.servlet.http.HttpServletRequest;/*** Interface to be implemented by objects that define a mapping between* requests and handler objects.** <p>This class can be implemented by application developers, although this is not* necessary, as {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping}* and {@link org.springframework.web.servlet.handler.SimpleUrlHandlerMapping}* are included in the framework. The former is the default if no* HandlerMapping bean is registered in the application context.** <p>HandlerMapping implementations can support mapped interceptors but do not* have to. A handler will always be wrapped in a {@link HandlerExecutionChain}* instance, optionally accompanied by some {@link HandlerInterceptor} instances.* The DispatcherServlet will first call each HandlerInterceptor's* <code>preHandle</code> method in the given order, finally invoking the handler* itself if all <code>preHandle</code> methods have returned <code>true</code>.** <p>The ability to parameterize this mapping is a powerful and unusual* capability of this MVC framework. For example, it is possible to write* a custom mapping based on session state, cookie state or many other* variables. No other MVC framework seems to be equally flexible.** <p>Note: Implementations can implement the {@link org.springframework.core.Ordered}* interface to be able to specify a sorting order and thus a priority for getting* applied by DispatcherServlet. Non-Ordered instances get treated as lowest priority.** @author Rod Johnson* @author Juergen Hoeller* @see org.springframework.core.Ordered* @see org.springframework.web.servlet.handler.AbstractHandlerMapping* @see org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping* @see org.springframework.web.servlet.handler.SimpleUrlHandlerMapping*/
public interface HandlerMapping {/*** Name of the {@link HttpServletRequest} attribute that contains the path* within the handler mapping, in case of a pattern match, or the full* relevant URI (typically within the DispatcherServlet's mapping) else.* <p>Note: This attribute is not required to be supported by all* HandlerMapping implementations. URL-based HandlerMappings will* typically support it, but handlers should not necessarily expect* this request attribute to be present in all scenarios.*/String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";/*** Name of the {@link HttpServletRequest} attribute that contains the* best matching pattern within the handler mapping.* <p>Note: This attribute is not required to be supported by all* HandlerMapping implementations. URL-based HandlerMappings will* typically support it, but handlers should not necessarily expect* this request attribute to be present in all scenarios.*/String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";/*** Name of the {@link HttpServletRequest} attribute that contains the URI* templates map, mapping variable names to values.* <p>Note: This attribute is not required to be supported by all* HandlerMapping implementations. URL-based HandlerMappings will* typically support it, but handlers should not necessarily expect* this request attribute to be present in all scenarios.*/String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";/*** Return a handler and any interceptors for this request. The choice may be made* on request URL, session state, or any factor the implementing class chooses.* <p>The returned HandlerExecutionChain contains a handler Object, rather than* even a tag interface, so that handlers are not constrained in any way.* For example, a HandlerAdapter could be written to allow another framework's* handler objects to be used.* <p>Returns <code>null</code> if no match was found. This is not an error.* The DispatcherServlet will query all registered HandlerMapping beans to find* a match, and only decide there is an error if none can find a handler.* @param request current HTTP request* @return a HandlerExecutionChain instance containing handler object and* any interceptors, or <code>null</code> if no mapping found* @throws Exception if there is an internal error*/HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;}

我们重点关注的HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception方法只有一个实现者,在

AbstractHandlerMapping类当中

/*** 为参数request查找对应的handler, 查找失败则返回默认的handler* @param request current HTTP request* @return the corresponding handler instance, or the default handler* @see #getHandlerInternal*/public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {Object handler = getHandlerInternal(request);if (handler == null) {handler = getDefaultHandler();}if (handler == null) {return null;}// Bean name or resolved handler?if (handler instanceof String) {String handlerName = (String) handler;handler = getApplicationContext().getBean(handlerName);}return getHandlerExecutionChain(handler, request);}

Abstract当中的getHandlerExecutionChain方法

  protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request){HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain) ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);chain.addInterceptors(getAdaptedInterceptors());String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {chain.addInterceptor(mappedInterceptor.getInterceptor());}}return chain;}

  

继续返回doDispatcher方法,获得了HandlerExecutionChain之后,构造了一个HandlerAdapter

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

最后我们发现是通过HandlerAdapter的handle方法产生的ModelAndView

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

  

转载于:https://www.cnblogs.com/wuxinliulei/p/5061220.html

SpringMVC源码阅读(一)相关推荐

  1. SpringMVC源码阅读:过滤器

    SpringMVC源码阅读:过滤器 目录 1.前言 2.源码分析 3.自定义过滤器 3.1 自定义过滤器继承OncePerRequestFilter 3.2 自定义过滤器实现Filter接口 4.过滤 ...

  2. SpringMVC源码阅读系列汇总

    1.前言 1.1 导入 SpringMVC是基于Servlet和Spring框架设计的Web框架,做JavaWeb的同学应该都知道 本文基于Spring4.3.7源码分析,(不要被图片欺骗了,手动滑稽 ...

  3. springmvc源码阅读3--dispatcherServlet reqeust的执行流程

    一.前言 太多的时候总是会遇到群里面问,报404怎么肥事呀,前台的参数怎么后台收不到呀--,上次就在群里面遇到过,围绕这一个点:input的name值是不是错了呀,人家妹子都截了好几次图说没有问题,然 ...

  4. SpringMVC源码阅读(三)

    先理一下Bean的初始化路线 org.springframework.beans.factory.support.AbstractBeanDefinitionReader public int loa ...

  5. SpringMVC源码分析系列[转]

    说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...

  6. SpringMVC源码分析系列

    说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...

  7. 应用监控CAT之cat-client源码阅读(一)

    CAT 由大众点评开发的,基于 Java 的实时应用监控平台,包括实时应用监控,业务监控.对于及时发现线上问题非常有用.(不知道大家有没有在用) 应用自然是最初级的,用完之后,还想了解下其背后的原理, ...

  8. centos下将vim配置为强大的源码阅读器

    每日杂事缠身,让自己在不断得烦扰之后终于有了自己的清静时光来熟悉一下我的工具,每次熟悉源码都需要先在windows端改好,拖到linux端,再编译.出现问题,还得重新回到windows端,这个过程太耗 ...

  9. 源码阅读:AFNetworking(十六)——UIWebView+AFNetworking

    该文章阅读的AFNetworking的版本为3.2.0. 这个分类提供了对请求周期进行控制的方法,包括进度监控.成功和失败的回调. 1.接口文件 1.1.属性 /**网络会话管理者对象*/ @prop ...

最新文章

  1. 服务认证暴力破解工具Crowbar
  2. 这段AI的深情告白在外网爆火:我并非真实,从未出生,永不死亡,你能爱我吗?...
  3. 2038问题 linux_Linux 文件系统类型导览
  4. Java SimpleTimeZone toString()方法与示例
  5. dj鲜生-22-模板抽离-列表页详情页模板的抽离-base_detail_list
  6. 上海石库门建筑群中规模最大的张园 迎来历史性的“重生”
  7. java程序设计图形题_面向对象与Java程序设计基础题目:设计一个程序可以一计算平面图形的面积和立体图形的体积。1.使用interface关键...
  8. canvas drawbitmap不出现_JS实现简单的画板(canvas),可在PC和移动端实现。
  9. mysql8 groups关键字
  10. Latex中导入VISIO图片
  11. minst 手写数字识别实战
  12. 怎样用等价类划分设计测试用例
  13. 重磅!Spring Cloud 生态再添新套件:Spring Cloud Tencent
  14. 大数据开发工程师是做什么的?岗位要求高吗?
  15. VSCode的VUE项目侧边栏打开资源管理器中的NPM脚本
  16. 微软严厉抨击谷歌与雅虎日本达成搜索合作交易
  17. C++笔记--Linux网络编程(15-0)-socket(供自查,文档说明)
  18. 秒懂FPGA、单片机、DSP、ASIC的区别
  19. 模电知识体系总结-1.1半导体基础器件
  20. matlab三维数据切片二维

热门文章

  1. 从github上下载单个文件
  2. Modularity(模块化-AMD规范)
  3. 构造函数与toString
  4. 7-169 汉密尔顿回路 (25 分)
  5. 7-48 字符串输入练习 (I) (15 分)
  6. 桌面环境选择_Ubuntu 18.04 桌面环境初体验
  7. veket linux软件下载6,veket linux官方
  8. android 在线设计工具,21个免费的UI界面设计工具、资源及网站
  9. 如何简单区分web前后端与MVC框架
  10. keil C51 例子