在这里会对各个组件进行宏观的介绍,在之后会详细介绍每个组件
HandlerMapping
它会根据request找到对应的处理器
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;
}
在查找的时候不单单只会返回给我们一个handler,还会将相关的拦截器和handler组成一个HandlerExecutionChain返回。
HandlerAdapter
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
它里面一共三个方法:
supports:判断是否可以使用某个Handler
handle:使用Handler来干活
getLastModified:获取资源的Last-Modified,它保存着资源最后一次修改的时间
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
HandlerExceptionResolver:根据异常设置ModelAndView,之后再通过render方法进行渲染
public interface HandlerExceptionResolver {
ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
在这个接口里面只定义了一个方法,他只需要根据错误类型解析出对应的ModelView
ViewResolver:将String类型的视图名和Locale解析为View类型的视图
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}
BeanNameViewResolver是根据ViewName从ApplicationContext容器中查找响应的bean做View的,我们看一下它的源码:
public class BeanNameViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered {
private int order = Integer.MAX_VALUE; // default: same as non-Ordered
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public View resolveViewName(String viewName, Locale locale) throws BeansException {
ApplicationContext context = getApplicationContext();
if (!context.containsBean(viewName)) {
if (logger.isDebugEnabled()) {
logger.debug("No matching bean found for view name '" + viewName + "'");
}
// Allow for ViewResolver chaining...
return null;
}
if (!context.isTypeMatch(viewName, View.class)) {
if (logger.isDebugEnabled()) {
logger.debug("Found matching bean for view name '" + viewName +
"' - to be ignored since it does not implement View");
}
// Since we're looking into the general ApplicationContext here,
// let's accept this as a non-match and allow for chaining as well...
return null;
}
return context.getBean(viewName, View.class);
}
}
根据viewName中Spring容器中查找Bean,如果查找不到或者查到后不是View类型则返回null,否则返回bean。
RequestToViewNameTranslator:ViewResolver是根据ViewName查找View,但有的Handler处理完后并没有设置View也没有设置viewName,这时就需要从request获取viewName
public interface RequestToViewNameTranslator {
/**
* Translate the given {@link HttpServletRequest} into a view name.
* @param request the incoming {@link HttpServletRequest} providing
* the context from which a view name is to be resolved
* @return the view name (or {@code null} if no default found)
* @throws Exception if view name translation fails
*/
String getViewName(HttpServletRequest request) throws Exception;
}
这是它的接口定义,RequestToViewNameTranslator再SpringMVC容器里只可以配置一个,所以所有request到viewName的转换规则都要在一个Translator里面全部实现。
LocaleResolver:用于从request解析出Locale
public interface LocaleResolver {
/**
* Resolve the current locale via the given request. Can return a default locale as
* fallback in any case.
* @param request the request to resolve the locale for
* @return the current locale (never {@code null})
*/
Locale resolveLocale(HttpServletRequest request);
/**
* Set the current locale to the given one.
* @param request the request to be used for locale modification
* @param response the response to be used for locale modification
* @param locale the new locale, or {@code null} to clear the locale
* @throws UnsupportedOperationException if the LocaleResolver implementation does not
* support dynamic changing of the locale
*/
void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale);
}
ThemeResolver:解析主题,主题是通过一系列资源来具体体现的,要得到一个主题首先需要ThemeResolver根据Request解析出ThemeName,然后ThemeSource根据这个名字找到对应的Theme。
public interface ThemeResolver {
/**
* Resolve the current theme name via the given request.
* Should return a default theme as fallback in any case.
* @param request request to be used for resolution
* @return the current theme name
*/
String resolveThemeName(HttpServletRequest request);
/**
* Set the current theme name to the given one.
* @param request request to be used for theme name modification
* @param response response to be used for theme name modification
* @param themeName the new theme name
* @throws UnsupportedOperationException if the ThemeResolver implementation
* does not support dynamic changing of the theme
*/
void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName);
}
MultipartResolver:用于处理上传请求,处理方法是将普通的request包装成MultipartHttpServletRequest,后者可以直接调用getFile方法获取到File,如果上传多个文件,还可以调用getFileMap得到FileName->File结构的Map
public interface MultipartResolver {
/**
* Determine if the given request contains multipart content.
* <p>Will typically check for content type "multipart/form-data", but the actually
* accepted requests might depend on the capabilities of the resolver implementation.
* @param request the servlet request to be evaluated
* @return whether the request contains multipart content
*/
boolean isMultipart(HttpServletRequest request);
/**
* Parse the given HTTP request into multipart files and parameters,
* and wrap the request inside a
* {@link org.springframework.web.multipart.MultipartHttpServletRequest} object
* that provides access to file descriptors and makes contained
* parameters accessible via the standard ServletRequest methods.
* @param request the servlet request to wrap (must be of a multipart content type)
* @return the wrapped servlet request
* @throws MultipartException if the servlet request is not multipart, or if
* implementation-specific problems are encountered (such as exceeding file size limits)
* @see MultipartHttpServletRequest#getFile
* @see MultipartHttpServletRequest#getFileNames
* @see MultipartHttpServletRequest#getFileMap
* @see javax.servlet.http.HttpServletRequest#getParameter
* @see javax.servlet.http.HttpServletRequest#getParameterNames
* @see javax.servlet.http.HttpServletRequest#getParameterMap
*/
MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException;
/**
* Cleanup any resources used for the multipart handling,
* like a storage for the uploaded files.
* @param request the request to cleanup resources for
*/
void cleanupMultipart(MultipartHttpServletRequest request);
}
FlashMapManager:FlashMap主要用在redirect中传递参数。而FlashMapManager是用来管理FlashMap的
public interface FlashMapManager {
/**
* Find a FlashMap saved by a previous request that matches to the current
* request, remove it from underlying storage, and also remove other
* expired FlashMap instances.
* <p>This method is invoked in the beginning of every request in contrast
* to {@link #saveOutputFlashMap}, which is invoked only when there are
* flash attributes to be saved - i.e. before a redirect.
* @param request the current request
* @param response the current response
* @return a FlashMap matching the current request or {@code null}
*/
FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);
/**
* Save the given FlashMap, in some underlying storage and set the start
* of its expiration period.
* <p><strong>NOTE:</strong> Invoke this method prior to a redirect in order
* to allow saving the FlashMap in the HTTP session or in a response
* cookie before the response is committed.
* @param flashMap the FlashMap to save
* @param request the current request
* @param response the current response
*/
void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}
整个redirect的参数通过FlashMap传递的过程分为三步:
1、在处理器中将需要传递的参数设置到outputFlashMap中,设置方法是request.getAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE)拿到outputFlashMap,然后将参数设置进去
2、在RedirectView的renderMergedOutputModel方法中调用FlashMapManager的saveOutputFlashMap方法,将outputFlashMap中的参数设置到Session中
3、请求redirect后DispatcherServlet的doService会调用FlashMapManager的retrieveAndUpdate方法从Session中获取inputFlashMap并设置到Request的属性中备用,同时从Session中删除