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
*/
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { processRequest(request, response);
}
/**
* Delegate POST requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected 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.
*/
@Override
protected 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
*/
@Deprecated
protected 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());

  

SpringMVC源码阅读(一)的更多相关文章

  1. SpringMVC源码阅读:过滤器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  2. SpringMVC源码阅读系列汇总

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

  3. SpringMVC源码阅读:属性编辑器、数据绑定

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  4. SpringMVC源码阅读:拦截器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  5. SpringMVC源码阅读:核心分发器DispatcherServlet

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将介绍SpringMVC的核 ...

  6. SpringMVC源码阅读:定位Controller

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码分析,弄清楚Spr ...

  7. SpringMVC源码阅读:Controller中参数解析

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  8. SpringMVC源码阅读:Json,Xml自动转换

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  9. SpringMVC源码阅读:视图解析器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  10. SpringMVC源码阅读:异常解析器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

随机推荐

  1. Making the Elephant Dance: Strategic Enterprise Analysis

    http://www.modernanalyst.com/Resources/Articles/tabid/115/ID/2934/categoryId/23/Making-the-Elephant- ...

  2. [互联网面试笔试汇总C/C++-7] 寻找两个链表的第一个交点-微策略

    题目:有两个链表,找出他们的第一个交点,要求每个链表只能遍历一次,可以对链表进行任何操作,空间O(1). 思路: 这个题目刚开始看觉得要遍历一次有点困难,但是仔细一想,人家告诉说可以对链表进行任何操作 ...

  3. 懂,你的App生,不懂,死!

    近期有一些开发人员.创业公司的人加我微信viyi88,咨询一些关于自己App的事情.被问得最多的可能就是:"我的App怎样推广添加下载量?"而且信誓旦旦地说自己的App做得非常好, ...

  4. apache kafka源码分析-Producer分析---转载

    原文地址:http://www.aboutyun.com/thread-9938-1-1.html 问题导读1.Kafka提供了Producer类作为java producer的api,此类有几种发送 ...

  5. Mybatis高级应用

    Mybatis是一个半自动的框架.相对于hibernate全自动模式,mybatis为开发人员提供了更加灵活的对sql语句操作的控制能力,有利于dba对相关的sql操作进行优化,同时也方便开发者构建复 ...

  6. 用php切割大图片为成规则的小图

    将根据xml配置,将合并后的大图切割成一系列小图 <?php /** * 将大图片按照配置切割成一定比例的小图片 * 并按照一定规则给小图片命名 * * 使用方法: *根据guardians/g ...

  7. ASP.NET中常用重置数据的方法

    aspx: <asp:Repeater ID="rptProlist" runat="server" onitemdatabound="rptP ...

  8. java 反射,注解,泛型,内省(高级知识点)

     Java反射 1.Java反射是Java被视为动态(或准动态)语言的一个关键性质.这个机制允许程序在运行时透过Reflection APIs    取得任何一个已知名称的class的内部信息, 包括 ...

  9. .Net开源SqlServer ORM框架SqlSugar整理

    一.链接整理 官方Git源代码地址: https://github.com/sunkaixuan/SqlSugar 最新发布版更新地址:当前版本Release 3.5.2.1 https://gith ...

  10. [DEncrypt] MySecurity--安全加密/Base64/文件加密 (转载)

    点击下载 MySecurity.zip 这个类是关于加密,解密的操作,文件的一些高级操作1.MySecurity  加密字符串2.MySecurity  加密字符串 密钥为系统默认 012345678 ...