Spring之SpringMVC(源码)初始化DispatcherServlet策略配置
1.从上一篇文章中可以SpringMVC初始化的过程中完成的其中一件事就是DispatcherServlet的相关策略的配置,如下所示
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
下面分别看下,每个策略配置的具体实现
2.文件类型解析器
private void initMultipartResolver(ApplicationContext context) { try {
//public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver" 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"); } } }
通过初始化这个类来处理文件解析,但是也可以发现如果没有提供的话,就会给出一个空的的解析器。
3. LocaleResolver解析器
private void initLocaleResolver(ApplicationContext context) {
try {// public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
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 + "]");
}
}
}
为了让web应用程序支持国际化,必须识别每个用户的首选区域,并根据这个区域显示内容。LocaleResolver解析器主要解决国际化的问题。如果配置了那么就使用所配置的解析器,如果没有配置的话,那么就是用默认提供的AcceptHeaderLocaleResolver。
4.ThemeResolver
主题样式解析器,
private void initThemeResolver(ApplicationContext context) {
try {// public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
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 + "]");
}
}
}
如果提供了提供了相应的主题解析器,那么就是用,否则的话就是提供一个默认的FixedThemeResolver来作为主题解析器,
5.处理器映射解析器
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. } }
请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象;BeanNameUrlHandlerMapping将URL与Bean名字映射,映射成功的Bean就是此处的处理器;通过这个类来初始化HandlerMappings,主要完成请求和处理器之间的映射关系。如果没有提供的话那么就会使用默认的BeanNameUrlHandlerMapping来进项相关的处理。我们来看下大致的处理过程。首先会获取所有的处理映射,然后对这些请求映射进项排序;如果请求映射集合为空,那么就会找到系统中的HandlerMapping,并且进行单例操作处理。如果这个HandlerMapping对象为空,就会使用默认的HandlerMapping,也就是BeanNameUrlHandlerMapping。
6.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"); } } }
HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器。也就是说按照特定规则(HandlerAdapter要求的规则)去执行Handler。它会首先获取ApplicationContext中所有的处理适配器,如果获取集合不为空,需要进行排序处理。没有找到,则会查找系统中的handlerAdapter,然后进行单例化处理。如果查找的系统handlerAdapter为空,则使用默认的适配器,也即是SimpleControllerHandlerAdapter,它将对实现了Controller接口的Bean进行适配,并且掉处理器的handleRequest方法进行功能处理。
7.HandlerExceptionResolver
private void initHandlerExceptionResolvers(ApplicationContext context) { this.handlerExceptionResolvers = null; if (this.detectAllHandlerExceptionResolvers) { // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts. Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values()); // We keep HandlerExceptionResolvers in sorted order. OrderComparator.sort(this.handlerExceptionResolvers); } } else { try { HandlerExceptionResolver her = context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class); this.handlerExceptionResolvers = Collections.singletonList(her); } catch (NoSuchBeanDefinitionException ex) { // Ignore, no HandlerExceptionResolver is fine too. } } // Ensure we have at least some HandlerExceptionResolvers, by registering // default HandlerExceptionResolvers if no other resolvers are found. if (this.handlerExceptionResolvers == null) { this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default"); } } }
通过这个方法来初始化HandlerExceptionResolver,如果没有配置,系统默认不会提供处理器异常解析器,会给一个空的来作为默认。它首先会查找ApplicationContext中所有的配置的处理器异常解析器,包括它的父容器的范围的,如果找到了会进行有序处理操作( Map<String, HandlerExceptionResolver>);如果找不到具体的映射配置,那么就会获取ApplicationContext中的HandlerExceptionResolver并且进行单例化处理。如果获取的这个解析器为空,那么就会使用默认的,也就是空的解析器处理。
8.RequestToViewNameTranslator
private void initRequestToViewNameTranslator(ApplicationContext context) { try { this.viewNameTranslator = context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class); if (logger.isDebugEnabled()) { logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]"); } } catch (NoSuchBeanDefinitionException ex) { // We need to use the default. this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class); if (logger.isDebugEnabled()) { logger.debug("Unable to locate RequestToViewNameTranslator with name '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator + "]"); } } }
通过提供的 Servlet实例来初始化RequestToViewNameTranslator,如果没有提供的话,就会使用系统默认的DefaultRequestToViewNameTranslator。
9.视图解析器
private void initViewResolvers(ApplicationContext context) { this.viewResolvers = null; if (this.detectAllViewResolvers) { // Find all ViewResolvers in the ApplicationContext, including ancestor contexts. Map<String, ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values()); // We keep ViewResolvers in sorted order. OrderComparator.sort(this.viewResolvers); } } else { try { ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class); this.viewResolvers = Collections.singletonList(vr); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default ViewResolver later. } } // Ensure we have at least one ViewResolver, by registering // a default ViewResolver if no other resolvers are found. if (this.viewResolvers == null) { this.viewResolvers = getDefaultStrategies(context, ViewResolver.class); if (logger.isDebugEnabled()) { logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default"); } } }
通过这个来进行视图解析器的初始化工作,如果没有提供的话那么就会使用InternalResourceViewResolver来进行处理,是不是对JSP页面处理的时候经常看到这个配置。
10.FlashMapManager
private void initFlashMapManager(ApplicationContext context) { try { this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class); if (logger.isDebugEnabled()) { logger.debug("Using FlashMapManager [" + this.flashMapManager + "]"); } } catch (NoSuchBeanDefinitionException ex) { // We need to use the default. this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class); if (logger.isDebugEnabled()) { logger.debug("Unable to locate FlashMapManager with name '" + FLASH_MAP_MANAGER_BEAN_NAME + "': using default [" + this.flashMapManager + "]"); } } }
从方法中的注释可知,如果用户没有提供它的配置,那么就是使用spring提供的org.springframework.web.servlet.support.DefaultFlashMapManager来作为默认的处理。
11.常量配置
11.1关于上面的初始化的配置常量
/** Well-known name for the MultipartResolver object in the bean factory for this namespace. */ public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver"; /** Well-known name for the LocaleResolver object in the bean factory for this namespace. */ public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver"; /** Well-known name for the ThemeResolver object in the bean factory for this namespace. */ public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver"; /** * Well-known name for the HandlerMapping object in the bean factory for this namespace. * Only used when "detectAllHandlerMappings" is turned off. * @see #setDetectAllHandlerMappings */ public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping"; /** * Well-known name for the HandlerAdapter object in the bean factory for this namespace. * Only used when "detectAllHandlerAdapters" is turned off. * @see #setDetectAllHandlerAdapters */ public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter"; /** * Well-known name for the HandlerExceptionResolver object in the bean factory for this namespace. * Only used when "detectAllHandlerExceptionResolvers" is turned off. * @see #setDetectAllHandlerExceptionResolvers */ public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver"; /** * Well-known name for the RequestToViewNameTranslator object in the bean factory for this namespace. */ public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator"; /** * Well-known name for the ViewResolver object in the bean factory for this namespace. * Only used when "detectAllViewResolvers" is turned off. * @see #setDetectAllViewResolvers */ public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver"; /** * Well-known name for the FlashMapManager object in the bean factory for this namespace. */ public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager"; /** * Request attribute to hold the current web application context. * Otherwise only the global web app context is obtainable by tags etc. * @see org.springframework.web.servlet.support.RequestContextUtils#getWebApplicationContext */ public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT"; /** * Request attribute to hold the current LocaleResolver, retrievable by views. * @see org.springframework.web.servlet.support.RequestContextUtils#getLocaleResolver */ public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER"; /** * Request attribute to hold the current ThemeResolver, retrievable by views. * @see org.springframework.web.servlet.support.RequestContextUtils#getThemeResolver */ public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER"; /** * Request attribute to hold the current ThemeSource, retrievable by views. * @see org.springframework.web.servlet.support.RequestContextUtils#getThemeSource */ public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE"; /** * Name of request attribute that holds a read-only {@code Map<String,?>} * with "input" flash attributes saved by a previous request, if any. * @see org.springframework.web.servlet.support.RequestContextUtils#getInputFlashMap(HttpServletRequest) */ public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP"; /** * Name of request attribute that holds the "output" {@link FlashMap} with * attributes to save for a subsequent request. * @see org.springframework.web.servlet.support.RequestContextUtils#getOutputFlashMap(HttpServletRequest) */ public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP"; /** * Name of request attribute that holds the {@link FlashMapManager}. * @see org.springframework.web.servlet.support.RequestContextUtils#getFlashMapManager(HttpServletRequest) */ public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER"; /** Log category to use when no mapped handler is found for a request. */ public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound"; /** * Name of the class path resource (relative to the DispatcherServlet class) * that defines DispatcherServlet's default strategy names. */ private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
11.2Spring提供的默认配置文件DispatcherServlet.properties
# Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
有上面的SpringMVC默认的配置文件可知,相应的策略实现有系统默认的配置项。