SpringMVC源码解读--DispatcherServlet类
Posted 低调的洋仔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC源码解读--DispatcherServlet类相关的知识,希望对你有一定的参考价值。
DispatcherServelet继承自FrameworkServlet类,然后FrameworkServlet类继承自HttpServletBean类,HttpServletBean类继承了HttpServlet类。
那么接收来的请求将会从GenericServelt进而传递给HttpServelt然后传递给HttpServeltBean来,然后接下来是FrameworkServlet类。
初始化的时候
/**
* Map config parameters onto bean properties of this servlet, and
* invoke subclass initialization.
* @throws ServletException if bean properties are invalid (or required
* properties are missing), or if subclass initialization fails.
*/
@Override
public final void init() throws ServletException
if (logger.isDebugEnabled())
logger.debug("Initializing servlet '" + getServletName() + "'");
// Set bean properties from init parameters.
try // ServletConfigPropertyValues是内部类,然后使用servletconfig来加载配置文件web.xml中的参数,并设置到其内部
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);// 模版方法可以在子类中调用,bw就是DispatcherServlet了。
bw.setPropertyValues(pvs, true);// 将配置的初始化值设置到DispatcherServelt中去。
catch (BeansException ex)
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
// Let subclasses do whatever initialization they like.
initServletBean();// 模版方法,子类初始化的模版方法
if (logger.isDebugEnabled())
logger.debug("Servlet '" + getServletName() + "' configured successfully");
接下来上面的那个initServletBean的方法.
@Override
protected final void initServletBean() throws ServletException
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled())
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
long startTime = System.currentTimeMillis();
try // 初始化WebApplicationContext
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();// 初始化FrameworkServlet
catch (ServletException ex)
this.logger.error("Context initialization failed", ex);
throw ex;
catch (RuntimeException ex)
this.logger.error("Context initialization failed", ex);
throw ex;
if (this.logger.isInfoEnabled())
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();// 初始化FrameworkServlet
catch (ServletException ex)
this.logger.error("Context initialization failed", ex);
throw ex;
catch (RuntimeException ex)
this.logger.error("Context initialization failed", ex);
throw ex;
if (this.logger.isInfoEnabled())
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
这个方法主要是初始化了WebApplicationServlet,initFrameworkServlet主要是个空的方法,用于子类去实现了。
/**
* Initialize and publish the WebApplicationContext for this servlet.
* <p>Delegates to @link #createWebApplicationContext for actual creation
* of the context. Can be overridden in subclasses.
* @return the WebApplicationContext instance
* @see #FrameworkServlet(WebApplicationContext)
* @see #setContextClass
* @see #setContextConfigLocation
*/
protected WebApplicationContext initWebApplicationContext()
WebApplicationContext rootContext =// 获取rootContext
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null)
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext)
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive())
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null)
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
configureAndRefreshWebApplicationContext(cwac);
if (wac == null)
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();// 看是不是已经注册到serveltcontxt中去了
if (wac == null)
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);// 创建一个出来
if (!this.refreshEventReceived)
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);// 调用onRefresh方法,这里可以在子类重写
if (this.publishContext)
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);// 将WebApplicationContext设置到ServeltContext中去。
if (this.logger.isDebugEnabled())
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
return wac;
setParent(rootContext);
configureAndRefreshWebApplicationContext(cwac);
if (wac == null)
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();// 看是不是已经注册到serveltcontxt中去了
if (wac == null)
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);// 创建一个出来
if (!this.refreshEventReceived)
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);// 调用onRefresh方法,这里可以在子类重写
if (this.publishContext)
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);// 将WebApplicationContext设置到ServeltContext中去。
if (this.logger.isDebugEnabled())
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
return wac;
三件事:
1. 获取spring的根容器rootContext.-->这应该就是Spring本身的容器了
2.查看有没有WebApplicationContext并根据实际情况调用OnRefresh方法。
3.将webApplicationContext设置到ServeltContext中、
WebApplicationContext本身就是SpringMVC的容器,设置为Spring的子容器。
注意比较重要的一个点,为什么说SpringMVC中的容器是Spring中容器的子容器呢?
上面的代码中你会看到一点,就是设置parent,前面红色部分标注了出来。
这个RootContext这个地方实际上是
public static WebApplicationContext getWebApplicationContext(ServletContext sc)
return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
public interface WebApplicationContext extends ApplicationContext
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
String SCOPE_REQUEST = "request";
String SCOPE_SESSION = "session";
String SCOPE_GLOBAL_SESSION = "globalSession";
String SCOPE_APPLICATION = "application";
String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
ServletContext getServletContext();
这个类实际上是在Spring的context中的。
DispatcherServlet类
onRefresh方法
DispatcherServelet中实际上调用了onRefresh方法的。
@Override
protected void onRefresh(ApplicationContext context)
initStrategies(context);
初始化策略,这个模版方法。
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context)
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
initMultipartResolver方法
/**
* Initialize the MultipartResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* no multipart handling is provided.
*/
private void initMultipartResolver(ApplicationContext context)
try
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isDebugEnabled())
logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
catch (NoSuchBeanDefinitionException ex)
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isDebugEnabled())
logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
"': no multipart request handling provided");
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isDebugEnabled())
logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
"': no multipart request handling provided");
从容器中获取到multipartResolver的实例对象。默认的情况下,是没有multipartResolver的。
A strategy interface for multipart file upload resolution in accordance
这个是用于上传的数据解析器。
initLocaleResolver方法
both locale resolution via the request and locale modification via request and response.
通过请求和响应通过请求和区域设置修改本地语言解析。
/**
* Initialize the LocaleResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to AcceptHeaderLocaleResolver.
*/
private void initLocaleResolver(ApplicationContext context)
try
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isDebugEnabled())
logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
catch (NoSuchBeanDefinitionException ex)
// We need to use the default.
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isDebugEnabled())
logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver + "]");
initThemeResolver方法
/**
* Initialize the ThemeResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to a FixedThemeResolver.
*/
private void initThemeResolver(ApplicationContext context)
try
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
if (logger.isDebugEnabled())
logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
catch (NoSuchBeanDefinitionException ex)
// We need to use the default.
this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
if (logger.isDebugEnabled())
logger.debug(
"Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME + "': using default [" +
this.themeResolver + "]");
默认的策略
返回诸多的策略中首位的那个。
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface)
List<T> strategies = getDefaultStrategies(context, strategyInterface);
if (strategies.size() != 1)
throw new BeanInitializationException(
"DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
return strategies.get(0);
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface)
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);// 获取初始化策略
if (value != null)
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);// 按照获取到的类型进行按照逗号来切割。
List<T> strategies = new ArrayList<T>(classNames.length);
for (String className : classNames)
try
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
catch (ClassNotFoundException ex)
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
catch (LinkageError err)
throw new BeanInitializationException(
"Error loading DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]: problem with class file or dependent class", err);
return strategies;
else
return new LinkedList<T>();
ThemeResolver
样式
/**
* Initialize the ThemeResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to a FixedThemeResolver.
*/
private void initThemeResolver(ApplicationContext context)
try
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
if (logger.isDebugEnabled())
logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
catch (NoSuchBeanDefinitionException ex)
// We need to use the default.
this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
if (logger.isDebugEnabled())
logger.debug(
"Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME + "': using default [" +
this.themeResolver + "]");
默认的情况基本上和上面的方法是同一个方法,仅仅是参数不一样所以结果可能不一样而已。
HandlerMapping
/**
* Initialize the HandlerMappings used by this class.
* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
* we default to BeanNameUrlHandlerMapping.
*/
private void initHandlerMappings(ApplicationContext context)
this.handlerMappings = null;
if (this.detectAllHandlerMappings)
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty())
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
OrderComparator.sort(this.handlerMappings);
else
try
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
catch (NoSuchBeanDefinitionException ex)
// Ignore, we'll add a default HandlerMapping later.
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null)
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled())
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
默认的话直接调用的,这样返回的是多个的HandlerMapping.
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface)
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value != null)
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<T>(classNames.length);
for (String className : classNames)
try
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
catch (ClassNotFoundException ex)
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
catch (LinkageError err)
throw new BeanInitializationException(
"Error loading DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]: problem with class file or dependent class", err);
return strategies;
else
return new LinkedList<T>();
HandlerAdapter
private void initHandlerAdapters(ApplicationContext context)
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters)
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty())
this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
OrderComparator.sort(this.handlerAdapters);
else
try
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
catch (NoSuchBeanDefinitionException ex)
// Ignore, we'll add a default HandlerAdapter later.
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null)
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled())
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
请求如何处理?
HttpServlet中init方法结束会调用service方法来处理请求的。
接下来HttpServletBean没有对其进行重写,然后FrameworkServlet对其进行了重写。
protected void doTrace(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
if (this.dispatchTraceRequest)
processRequest(request, response);
if ("message/http".equals(response.getContentType()))
// Proper TRACE response coming from a handler - we're done.
return;
super.doTrace(request, response);
调用processRequest方法。
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
// 得到与当前线程绑定的LocaleContext和RequestAttributes的实例,然后
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
// 得到与当前线程绑定的LocaleContext和RequestAttributes的实例,然后
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
ServletRequestHandledEvent
initContextHolders(request, localeContext, requestAttributes);try doService(request, response);// 调用了DespatcherServlet中的方法。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 // 处理完成后解除LocaleContext和request的绑定,然后重置为以前的属性resetContextHolders(request, previousLocaleContext, previousAttributes);if (requestAttributes != null) requestAttributes.requestCompleted();if (logger.isDebugEnabled()) if (failureCause != null) this.logger.debug("Could not complete request", failureCause);else if (asyncManager.isConcurrentHandlingStarted()) logger.debug("Leaving response open for concurrent processing");else this.logger.debug("Successfully completed request"); // 发布请求处理事件publishRequestHandledEvent(request, response, startTime, failureCause);
initContextHolder方法
private void initContextHolders(
HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes)
if (localeContext != null)
LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
if (requestAttributes != null)
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
if (logger.isTraceEnabled())
logger.trace("Bound request context to thread: " + request);
调用的DespatcherServlet类中的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)) // 1
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());// 设置相应属性
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);
if (WebUtils.isIncludeRequest(request)) // 1
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());// 设置相应属性
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);
1.如果是include请求,那么保存一份快照数据,然后设置新的请求的数据,完成之后再进行覆盖。
最终doDispatch
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(request, 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);
// 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(request, 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);
找Handler对象,找完Handler对象之后再找HandlerAdapter对象。然后调用HandlerAdapter的handle方法来处理,接下来返回视图结果,然后将结果进行解析。。。
以上是关于SpringMVC源码解读--DispatcherServlet类的主要内容,如果未能解决你的问题,请参考以下文章
SpringMVC源码解读--HandlerAdapter源码解读
SpringMVC源码解读 - HandlerMapping
SpringMVC源码解读 - RequestMapping注解实现解读 - RequestMappingInfo
SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系