上一节谈到DispatcherServlet默认做了很多事情,默认的依赖Beans
本节探索具体的Beans
结论:
使用如下配置+DispatcherServlet进行SpringMVC的使用时
<mvc:annotation-driven ></mvc:annotation-driven>
DispatcherServlet默认依赖的Bean有
DispatcherServlet在通常使用情况下的默认引用(依赖)Beans 依赖的Beans 复数? 存在默认配置值? 装配方式 名称或类型 具体实现类 MutipartResolver no no 名称 multipartResolver 无 LocaleResolver no yes 名称 localeResolver org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver ThemeResolver no yes 名称 themeResolver org.springframework.web.servlet.theme.FixedThemeResolver RequestToViewNameTranslator no yes 名称 viewNameTranslator org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator FlashManager no yes 名称 flashManager org.springframework.web.servlet.support.SessionFlashMapManager HandlerMappings yes yes 类型 HandlerMapping org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping HandlerAdapters yes yes 类型 HandlerAdapter org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter HadnlerExceptionResolvers yes yes 类型 HadnlerExceptionResolver org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver ViewResolvers yes yes 类型 ViewResolver org.springframework.web.servlet.view.InternalResourceViewResolver
测试发现,当我们使用<mvc:annotation-driven >进行简单配置时,实际IOC容器中是重新定义了HandlerMappings、HandlerAdapters、HadnlerExceptionResolvers其他则是使用DispatherServlet.properties的默认配置。
也就是说<mvc:annotation-driven ></mvc:annotation-driven >,实际就是配置了HanleMappings、HandleMappingAdapters、HadnlerExceptionResolvers.
-
=========================重点 BEGIN=====================
- HandlerMapping
- 将传入的请求映射到处理程序和一个列表的前和后处理器(处理程序拦截器)基于某些标准随HandlerMapping实现的细节。【连接请求(request)与处理器+(前置、后置)拦截器的作用】
- HandlerAdapter
- 帮助DispatcherServlet去调用一个被请求映射的Handler,无论这个Handler是否会被真正的调用【适配Handler与HandlerMapping
- HandlerExceptionResolver
- Handler异常解析器
- ViewResolver
- 视图解析器
- LocaleResolver & LocaleContextResolver
- 本地化相关解析器
- =========================重点 END=====================
- ThemeResolver
- 主题解析器
- MultipartResolver
- mutipart解析器【应该是和文件上传有关吧,猜测】
- FlashMapManager
- Flash相关?
DispatcherServlet源码中
/** MultipartResolver used by this servlet */
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet */
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet */
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet */
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet */
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet */
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet */
private RequestToViewNameTranslator viewNameTranslator;
/** FlashMapManager used by this servlet */
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet */
private List<ViewResolver> viewResolvers;
值得注意的是handlerMappings、handlerAdapters、handlerExceptionResolvers、viewResolvers他们是List,我们可以配置多个。
# 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
大坑:发现DefaultAnnotationHandlerMapping已经被丢弃,由RequestMappingHandlerMapping取代但是在属性文件还是上面的配置
- The
WebApplicationContext
is searched for and bound in the request as an attribute that the controller and other elements in the process can use. It is bound by default under the keyDispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
. - The locale resolver is bound to the request to enable elements in the process to resolve the locale to use when processing the request (rendering the view, preparing data, and so on). If you do not need locale resolving, you do not need it.
- The theme resolver is bound to the request to let elements such as views determine which theme to use. If you do not use themes, you can ignore it.
- If you specify a multipart file resolver, the request is inspected for multiparts; if multiparts are found, the request is wrapped in a
MultipartHttpServletRequest
for further processing by other elements in the process. See Section 18.10, “Spring’s multipart (file upload) support” for further information about multipart handling. - An appropriate handler is searched for. If a handler is found, the execution chain associated with the handler (preprocessors, postprocessors, and controllers) is executed in order to prepare a model or rendering.
- If a model is returned, the view is rendered. If no model is returned, (may be due to a preprocessor or postprocessor intercepting the request, perhaps for security reasons), no view is rendered, because the request could already have been fulfilled.
- 搜索
WebApplicationContext
并将他绑定到请求Request的属性上,通过默认的名称DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
- 绑定local resolver(可选)
- 绑定theme resolver(可选)
- 如果指定了一个multipart file resolver,这个请求被检测到multiparts,请求将会包装为
MultipartHttpServletRequest
来被其他元素处理。 - 寻找一个合适的Handler,如果Handler被找到,为了得到一个model或者呈现而去执行相关的链(前置处理器、后置处理器和Controller)。
如果返回一个model,则视图被呈现,或者没有model返回。
DispatcherServlet源码分析,SpringMVC到底默认加了哪些Beans为我们服务?
/**
* 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);
}
initStrategies(ApplicationContext context)
在DispatcherServlet初始化时候被调用。由上面代码可以看到,在这里初始化了相关Beans。下面进行分析:
initMultipartResolver(context)//初始化MutipartResolver
/**
* 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");
}
}
}
没有默认的MutipartResolver
可以通过DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME(multipartResolver)名称在IOC容器中进行配置
initLocaleResolver(context)//初始化LocaleResolver
/**
* 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 + "]");
}
}
}
本地化解析器LocaleResolver是有默认Bean的呦!具体的方法就不再展示给出具体类型:DispatcherServlet.properties中
key为org.springframework.web.servlet.LocaleResolver(LocaleResolver类全名)的值
initThemeResolver(context)
/**
* 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 + "]");
}
}
}
存在默认Bean,也可以IOC中配置,配置会取代默认。
IOC配置名称:DispatcherServlet.THEME_RESOLVER_BEAN_NAME(themeResolver)
默认值:DispatcherServlet.properties中key:ThemeResolver.class全名的配置值
initRequestToViewNameTranslator(ApplicationContext context)
/**
* Initialize the RequestToViewNameTranslator used by this servlet instance.
* <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
*/
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 +
"]");
}
}
}
IOC没有配置ViewTranslator时使用属性文件默认值
initFlashMapManager(ApplicationContext context)
/**
* Initialize the RequestToViewNameTranslator used by this servlet instance.
* <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
*/
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 +
"]");
}
}
}
IOC没有配置FlashMapManager时使用属性文件默认值
initHandlerMappings(ApplicationContext context)
/**
* 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.
AnnotationAwareOrderComparator.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.
}
}
boolean detectAllHandlerMappings
默认为true,检查所有的HandlerMappings
默认情况下会在IOC容器中,而且是整个IOC容器中,查询所有的HandlerMapping的实现类,并经过Order排序组成一个HandlerMappings的List集合。
如果设置了detectAllHandlerMappings=false,
则只在IOC容器中查询名为DispatcherServlet.HANDLER_MAPPING_BEAN_NAME。此时也就是只有一个HandlerMapping。
注意:为了确保存在HanlerMappings,如果我们设置了detectAllHandlerMappings=false,但是在IOC容器中没有配置名称为handlerMapping的Bean,此时依旧会使用
默认配置(即属性文件里的配置)
initHandlerAdapters(ApplicationContext context)
initHandlerExceptionResolvers(ApplicationContext context)
initViewResolvers(ApplicationContext context)
与handlerMappings类似,不再赘述。附上源码
/**
* Initialize the HandlerAdapters used by this class.
* <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
* we default to SimpleControllerHandlerAdapter.
*/
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.
AnnotationAwareOrderComparator.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");
}
}
}
/**
* Initialize the HandlerExceptionResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to no exception resolver.
*/
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.
AnnotationAwareOrderComparator.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");
}
}
}
/**
* Initialize the ViewResolvers used by this class.
* <p>If no ViewResolver beans are defined in the BeanFactory for this
* namespace, we default to InternalResourceViewResolver.
*/
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.
AnnotationAwareOrderComparator.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");
}
}
}