SpringMVC源码情操陶冶-DispatcherServlet类简析(一)
阅读源码有利于陶冶情操,此文承接前文SpringMVC源码情操陶冶-DispatcherServlet父类简析
注意:springmvc初始化其他内容,其对应的配置文件已被加载至beanFactory中
DispatcherServlet#静态方法
DispatcherServlet静态块读取DispatcherServlet.properties,其中包含默认的策略实现
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}
简单看下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
#url映射
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
DispatcherServlet#onRefresh
复写父类FrameworkServlet
的onRefresh()方法,springmvc以此来完善相应的初始化操作,代码如下
//复写
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
直接看DispatcherServlet#initStrategies()
初始化springmvc的策略对象,代码如下
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
以上述程序的执行顺序,逐个分析
DispatcherServlet#initMultipartResolver(ApplicationContext context)
根据官方注释,此会去加载beanFactory的multipartResolver
bean对象,适用于处理文件上传的操作,简单代码如下
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");
}
}
}
DispatcherServlet#initLocaleResolver(ApplicationContext context)
本地校对解析,官方解释为获取id="localeResolver"
的bean对象,如果没有则使用默认的org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
类创建bean对象
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 + "]");
}
}
}
Note:这里我们简单看下
DispatcherServlet#getDefaultStrategy()
的内部方法createDefaultStrategy()
创建spring bean对象
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
//可通过ApplicationContext.getAutowireCapableBeanFactory()方法来额外的创建外部class为bean对象
return context.getAutowireCapableBeanFactory().createBean(clazz);
}
DispatcherServlet#initThemeResolver(ApplicationContext context)
同DispatcherServlet#initLocaleResolver(ApplicationContext context)
,找寻id="themeResolver"
的bean对象,没有则默认使用org.springframework.web.servlet.theme.FixedThemeResolver
作为bean对象
DispatcherServlet#initHandlerMappings(ApplicationContext context)
初始化对资源访问的映射处理类,代码如下
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
/***默认为true,表示从beanFactory和其父类获取所有的HandlerMapping
** beans
**<init-param>
* <param-name>detectAllHandlerMappings</param-name>
* <param-value>true/false</param-value>
*/
if (this.detectAllHandlerMappings) {
//从祖先类到子类都去找寻相应的资源
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 {
//否则获取本springmvc的上下文中的单个`id="handlerMapping"`的HandlerMapping bean
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.
}
}
//如果detectAllHandlerMappings=false且springmvc不包含相应的`handlerMapping`bean 则取默认的HandlerMappings
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
默认的HandlerMappings为org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
和
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
,从字面上可知前者是根据beanName直接映射请求,后者是注解方式的映射请求
DispatcherServlet#initHandlerAdapters(ApplicationContext context)
此处类似DispatcherServlet#initHandlerMapping()
:
detectAllHandlerAdapters
默认为true,也可通过web.xml修改值,表示找寻所有满足HandlerAdapter.class
的beans;若为false,则寻找springmvc本身上下文环境(springmvc配置文件)的id="handlerAdapter"
的单个bean对象。所以不管如何,springmvc若指定了handlerAdapter
bean,其总是会被加载默认的策略对象为
SimpleControllerHandlerAdapter
-简单的Controller请求处理
DispatcherServlet#initHandlerExceptionResolvers(ApplicationContext context)
此处类似DispatcherServlet#initHandlerMapping()
:
detectAllHandlerExceptionResolvers
默认为true,也可通过web.xml修改值,表示找寻所有满足HandlerExceptionResolver.class
的beans;若为false,则寻找springmvc本身上下文环境(springmvc配置文件)的id="handlerExceptionResolver"
的单个bean对象。所以不管如何,springmvc若指定了handlerExceptionResolver
bean,其总是会被加载默认的策略对象为
SimpleControllerHandlerAdapter
-简单的Controller请求处理
DispatcherServlet#initRequestToViewNameTranslator(ApplicationContext context)
此处同DispatcherServlet#initLocaleResolver()
方法
- 首先找寻springmvc上下文中的
id="viewNameTranslator"
的bean,类型为RequestToViewNameTranslator.class
- 不然则采用默认的策略对象
org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
-对请求的URI直接映射到view对象
DispatcherServlet#initViewResolvers(ApplicationContext context)
此处类似DispatcherServlet#initViewResolvers()
:
detectAllViewResolvers
默认为true,也可通过web.xml修改值,表示找寻所有满足ViewResolver.class
的beans;若为false,则寻找springmvc本身上下文环境(springmvc配置文件)的id="viewResolver"
的单个bean对象。所以不管如何,springmvc若指定了viewResolver
bean,其总是会被加载默认的策略对象为
InternalResourceViewResolver
-默认解析为jsp视图
DispatcherServlet#initFlashMapManager(ApplicationContext context)
此处同DispatcherServlet#initLocaleResolver()
方法
- 首先找寻springmvc上下文中的
id="flashMapManager"
的bean,类型为FlashMapManager.class
- 不然则采用默认的策略对象
org.springframework.web.servlet.support.SessionFlashMapManager
-保存并检索FlashMap
属性
小结
本文只介绍springmvc额外的初始化操作,包括文件上传处理类、请求映射处理类/适配器、异常处理类、视图解析类等等