首页 > 代码库 > Spring MVC之DispatcherServlet初始化
Spring MVC之DispatcherServlet初始化
今天在整合工作流activiti5.14时,部署到Tomcat中启动时看到console输出的信息中有如下信息,
2017-02-16 14:43:11,161 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean ‘org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor‘ 2017-02-16 14:43:11,161 DEBUG [org.springframework.web.context.support.XmlWebApplicationContext] - Unable to locate LifecycleProcessor with name ‘lifecycleProcessor‘: using default [org.springframework.context.support.DefaultLifecycleProcessor@13b070c] 2017-02-16 14:43:11,161 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean ‘lifecycleProcessor‘ 2017-02-16 14:43:11,163 DEBUG [org.springframework.web.servlet.DispatcherServlet] - Unable to locate MultipartResolver with name ‘multipartResolver‘: no multipart request handling provided 2017-02-16 14:43:11,164 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Creating instance of bean ‘org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver‘ 2017-02-16 14:43:11,166 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Finished creating instance of bean ‘org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver‘ 2017-02-16 14:43:11,167 DEBUG [org.springframework.web.servlet.DispatcherServlet] - Unable to locate LocaleResolver with name ‘localeResolver‘: using default [org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@109800a] 2017-02-16 14:43:11,169 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Creating instance of bean ‘org.springframework.web.servlet.theme.FixedThemeResolver‘
于是到网上查了下。
下面的内容转自:zhangwei_david,访问地址:http://wujiu.iteye.com/blog/2170778,感谢zhangwei_david的分享!
使用Spring MVC 时,需要在web.xml中配置DispatchServlet,这个DispatchServlet可以看成一个控制器的具体实现。作为一个控制器所有的请求都要通过它来处理,进行转发、匹配、数据处理后并转由页面进行展示。因此DispatchServlet是Spring MVC的核心部分。
在完成ContextLoaderListener的初始化后,Web容器开始初始化DispatcherServlet,这个初始化的启动与在web.xml中对载入次序的定义有关。DispathcerServlet会建立自己的上下文来持有Spring MVC的Bean,在建立这个自己的IOC容器时,会从ServletContext中得到根上下文作为自己持有上下文的双亲上下文。有了这个根上下文再对自己持有的上下文进行初始化,最后将自己持有的上下文保存到ServletContext中。
首先看看DispatcherSerlvet的继承关系:DispatcherServlet继承自FrameworkServlet,而FrameworkServet继承自HttpServletBean.HttpServletBean有继承了HttpServlet.
DispatcherServlet动作大致可以分为两个部分:初始化部分由initServletBean()启动,通过initWebApplicationContext()方法调用DispatcherServlet的initStrategies方法。在这个方法里,DispatcherServlet对MVC的其他部分进行了初始化,比如handlerMapping,ViewResolver;另一个部分是对Http的请求进行响应,作为一个Servlet,web容器会调用Servlet的doGet()和doPost()方法,在经过FrameServlet的processRequest()简单处理后,会调用DispatcherServlet的doService()方法,在这个方法中封装了doDispatch().
在这里主要介绍初始化部分。
作为Servlet, DispatcherServlet的启动过程和Servlet启动过程是相联系的。在Servlet的初始化过程中,Servlet的init方法被调用,已进行初始化。
HttppServletBean.init()->FrameworkServlet.initWebApplicationContext()->DispatcherServlet.onRefresh().
onRefresh 的源码是:
1 /** 2 * This implementation calls {@link #initStrategies}. 3 */ 4 @Override 5 protected void onRefresh(ApplicationContext context) { 6 initStrategies(context); 7 }
而initStrategies(context)的源码如下:
1 protected void initStrategies(ApplicationContext context) { 2 //初始化多媒体解析器 3 initMultipartResolver(context); 4 //初始化位置解析器 5 initLocaleResolver(context); 6 //初始化主题解析器 7 initThemeResolver(context); 8 //初始化HandlerMappings 9 initHandlerMappings(context); 10 // 初始化HandlerAdapters 11 initHandlerAdapters(context); 12 //初始化异常解析器 13 initHandlerExceptionResolvers(context); 14 //初始化请求到视图名转换器 15 initRequestToViewNameTranslator(context); 16 //初始化视图解析器 17 initViewResolvers(context); 18 //初始化FlashMapManager 19 initFlashMapManager(context); 20 }
通过initMultipartResover进行初始化多媒体解析器,如果在配置文件中没有配置id为multipartResolver的bean则没有提供多媒体处理器。
1 /** 2 * Initialize the MultipartResolver used by this class. 3 * <p>If no bean is defined with the given name in the BeanFactory for this namespace, 4 * no multipart handling is provided. 5 */ 6 private void initMultipartResolver(ApplicationContext context) { 7 try { 8 this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class); 9 if (logger.isDebugEnabled()) { 10 logger.debug("Using MultipartResolver [" + this.multipartResolver + "]"); 11 } 12 } 13 catch (NoSuchBeanDefinitionException ex) { 14 // Default is no multipart resolver. 15 this.multipartResolver = null; 16 if (logger.isDebugEnabled()) { 17 logger.debug("Unable to locate MultipartResolver with name ‘" + MULTIPART_RESOLVER_BEAN_NAME + 18 "‘: no multipart request handling provided"); 19 } 20 } 21 }
通过initLocaleResolver方法进行localeResolver的初始化,如果没有配置指定id为localeResolver的bean则使用AcceptHeaderLocaleResolver的位置解析器。
1 /* Initialize the LocaleResolver used by this class. 2 * <p>If no bean is defined with the given name in the BeanFactory for this namespace, 3 * we default to AcceptHeaderLocaleResolver. 4 */ 5 private void initLocaleResolver(ApplicationContext context) { 6 try { 7 this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class); 8 if (logger.isDebugEnabled()) { 9 logger.debug("Using LocaleResolver [" + this.localeResolver + "]"); 10 } 11 } 12 catch (NoSuchBeanDefinitionException ex) { 13 // We need to use the default. 14 this.localeResolver = getDefaultStrategy(context, LocaleResolver.class); 15 if (logger.isDebugEnabled()) { 16 logger.debug("Unable to locate LocaleResolver with name ‘" + LOCALE_RESOLVER_BEAN_NAME + 17 "‘: using default [" + this.localeResolver + "]"); 18 } 19 } 20 }
initThemeResolver初始化主题解析器,如果没有配置指定id的为themeResolver的bean 则使用FixedThemeResolver主题解析器。
1 /** 2 * Initialize the ThemeResolver used by this class. 3 * <p>If no bean is defined with the given name in the BeanFactory for this namespace, 4 * we default to a FixedThemeResolver. 5 */ 6 private void initThemeResolver(ApplicationContext context) { 7 try { 8 this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class); 9 if (logger.isDebugEnabled()) { 10 logger.debug("Using ThemeResolver [" + this.themeResolver + "]"); 11 } 12 } 13 catch (NoSuchBeanDefinitionException ex) { 14 // We need to use the default. 15 this.themeResolver = getDefaultStrategy(context, ThemeResolver.class); 16 if (logger.isDebugEnabled()) { 17 logger.debug( 18 "Unable to locate ThemeResolver with name ‘" + THEME_RESOLVER_BEAN_NAME + "‘: using default [" + 19 this.themeResolver + "]"); 20 } 21 } 22 }
初始化HandlerMapping,这个handlerMapping的作用是为Http请求找到相应的控制器,从而利用这些控制器去完成http请求的数据处理工作。这些控制器和http的请求时对应的。DispatcherServlet中handlerMapping的初始化过程中的具体实现如下。在HandlerMapping的初始化过程中,把Bean配置文件中配置好的handlerMapping从IOC容器中取出。
1 /** 2 * Initialize the HandlerMappings used by this class. 3 * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace, 4 * we default to BeanNameUrlHandlerMapping. 5 */ 6 private void initHandlerMappings(ApplicationContext context) { 7 this.handlerMappings = null; 8 9 if (this.detectAllHandlerMappings) { 10 // 在应用上下文包括其祖先上下文中查找所有HandlerMappings 11 Map<String, HandlerMapping> matchingBeans = 12 BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); 13 //如果matchingBeans这个map是不为空,则创建一个新的ArrayList 14 if (!matchingBeans.isEmpty()) { 15 this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); 16 //并对其进行排序 17 OrderComparator.sort(this.handlerMappings); 18 } 19 } 20 else { 21 try { 22 //从应用上下文中查找所有的HandlerMapping 23 HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); 24 this.handlerMappings = Collections.singletonList(hm); 25 } 26 catch (NoSuchBeanDefinitionException ex) { 27 // Ignore, we‘ll add a default HandlerMapping later. 28 } 29 } 30 31 // Ensure we have at least one HandlerMapping, by registering 32 // a default HandlerMapping if no other mappings are found. 33 if (this.handlerMappings == null) { 34 // 如果没有配置HandlerMapping 则使用默认的HandlerMapping 策略 35 this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); 36 if (logger.isDebugEnabled()) { 37 logger.debug("No HandlerMappings found in servlet ‘" + getServletName() + "‘: using default"); 38 } 39 } 40 }
经过上述的处理过程,handlerMapping已经初始化完成,handlerMapping中就已经获取了在BeanDefinition中配置的映射关系。
通过initHandlerAdapters进行初始化HandlerAdapter,如果没有配置HandlerAdapter则使用SimpleControllerHandlerAdapter。
1 /** 2 * Initialize the HandlerAdapters used by this class. 3 * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace, 4 * we default to SimpleControllerHandlerAdapter. 5 */ 6 private void initHandlerAdapters(ApplicationContext context) { 7 this.handlerAdapters = null; 8 9 if (this.detectAllHandlerAdapters) { 10 // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts. 11 Map<String, HandlerAdapter> matchingBeans = 12 BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); 13 if (!matchingBeans.isEmpty()) { 14 this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values()); 15 // We keep HandlerAdapters in sorted order. 16 OrderComparator.sort(this.handlerAdapters); 17 } 18 } 19 else { 20 try { 21 HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class); 22 this.handlerAdapters = Collections.singletonList(ha); 23 } 24 catch (NoSuchBeanDefinitionException ex) { 25 // Ignore, we‘ll add a default HandlerAdapter later. 26 } 27 } 28 29 // Ensure we have at least some HandlerAdapters, by registering 30 // default HandlerAdapters if no other adapters are found. 31 if (this.handlerAdapters == null) { 32 this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class); 33 if (logger.isDebugEnabled()) { 34 logger.debug("No HandlerAdapters found in servlet ‘" + getServletName() + "‘: using default"); 35 } 36 } 37 }
初始化异常处理器,如果没有配置指定Id为handlerExceptionResolver的Bean,默认是没有异常处理器。
1 /** 2 * Initialize the HandlerExceptionResolver used by this class. 3 * <p>If no bean is defined with the given name in the BeanFactory for this namespace, 4 * we default to no exception resolver. 5 */ 6 private void initHandlerExceptionResolvers(ApplicationContext context) { 7 this.handlerExceptionResolvers = null; 8 9 if (this.detectAllHandlerExceptionResolvers) { 10 // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts. 11 Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils 12 .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false); 13 if (!matchingBeans.isEmpty()) { 14 this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values()); 15 // We keep HandlerExceptionResolvers in sorted order. 16 OrderComparator.sort(this.handlerExceptionResolvers); 17 } 18 } 19 else { 20 try { 21 HandlerExceptionResolver her = 22 context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class); 23 this.handlerExceptionResolvers = Collections.singletonList(her); 24 } 25 catch (NoSuchBeanDefinitionException ex) { 26 // Ignore, no HandlerExceptionResolver is fine too. 27 } 28 } 29 30 // Ensure we have at least some HandlerExceptionResolvers, by registering 31 // default HandlerExceptionResolvers if no other resolvers are found. 32 if (this.handlerExceptionResolvers == null) { 33 this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class); 34 if (logger.isDebugEnabled()) { 35 logger.debug("No HandlerExceptionResolvers found in servlet ‘" + getServletName() + "‘: using default"); 36 } 37 } 38 }
初始化请求到视图名称的转换器,如果不配置则使用默认的转换器。
1 /** 2 * Initialize the RequestToViewNameTranslator used by this servlet instance. 3 * <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator. 4 */ 5 private void initRequestToViewNameTranslator(ApplicationContext context) { 6 try { 7 this.viewNameTranslator = 8 context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class); 9 if (logger.isDebugEnabled()) { 10 logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]"); 11 } 12 } 13 catch (NoSuchBeanDefinitionException ex) { 14 // We need to use the default. 15 this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class); 16 if (logger.isDebugEnabled()) { 17 logger.debug("Unable to locate RequestToViewNameTranslator with name ‘" + 18 REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "‘: using default [" + this.viewNameTranslator + 19 "]"); 20 } 21 } 22 }
初始化视图解析器,如果没有配置视图解析器则使用默认的InternalResourceViewResolver视图解析器。
1 /** 2 * Initialize the ViewResolvers used by this class. 3 * <p>If no ViewResolver beans are defined in the BeanFactory for this 4 * namespace, we default to InternalResourceViewResolver. 5 */ 6 private void initViewResolvers(ApplicationContext context) { 7 this.viewResolvers = null; 8 9 if (this.detectAllViewResolvers) { 10 // Find all ViewResolvers in the ApplicationContext, including ancestor contexts. 11 Map<String, ViewResolver> matchingBeans = 12 BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false); 13 if (!matchingBeans.isEmpty()) { 14 this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values()); 15 // We keep ViewResolvers in sorted order. 16 OrderComparator.sort(this.viewResolvers); 17 } 18 } 19 else { 20 try { 21 ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class); 22 this.viewResolvers = Collections.singletonList(vr); 23 } 24 catch (NoSuchBeanDefinitionException ex) { 25 // Ignore, we‘ll add a default ViewResolver later. 26 } 27 } 28 29 // Ensure we have at least one ViewResolver, by registering 30 // a default ViewResolver if no other resolvers are found. 31 if (this.viewResolvers == null) { 32 this.viewResolvers = getDefaultStrategies(context, ViewResolver.class); 33 if (logger.isDebugEnabled()) { 34 logger.debug("No ViewResolvers found in servlet ‘" + getServletName() + "‘: using default"); 35 } 36 } 37 }
获取默认设置,首先获取接口的名称,然后从DispatcherServlert.properties的配置文件中读取value,然后将其分割为字符串数组。
1 /** 2 * Create a List of default strategy objects for the given strategy interface. 3 * <p>The default implementation uses the "DispatcherServlet.properties" file (in the same 4 * package as the DispatcherServlet class) to determine the class names. It instantiates 5 * the strategy objects through the context‘s BeanFactory. 6 * @param context the current WebApplicationContext 7 * @param strategyInterface the strategy interface 8 * @return the List of corresponding strategy objects 9 */ 10 @SuppressWarnings("unchecked") 11 protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { 12 String key = strategyInterface.getName(); 13 String value =http://www.mamicode.com/ defaultStrategies.getProperty(key); 14 if (value != null) { 15 String[] classNames = StringUtils.commaDelimitedListToStringArray(value); 16 List<T> strategies = new ArrayList<T>(classNames.length); 17 for (String className : classNames) { 18 try { 19 Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); 20 Object strategy = createDefaultStrategy(context, clazz); 21 strategies.add((T) strategy); 22 } 23 catch (ClassNotFoundException ex) { 24 throw new BeanInitializationException( 25 "Could not find DispatcherServlet‘s default strategy class [" + className + 26 "] for interface [" + key + "]", ex); 27 } 28 catch (LinkageError err) { 29 throw new BeanInitializationException( 30 "Error loading DispatcherServlet‘s default strategy class [" + className + 31 "] for interface [" + key + "]: problem with class file or dependent class", err); 32 } 33 } 34 return strategies; 35 } 36 else { 37 return new LinkedList<T>(); 38 } 39 }
DispatcherSerlvet.properties
1 # Default implementation classes for DispatcherServlet‘s strategy interfaces. 2 # Used as fallback when no matching beans are found in the DispatcherServlet context. 3 # Not meant to be customized by application developers. 4 5 org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver 6 7 org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver 8 9 org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ 10 org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping 11 12 org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ 13 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ 14 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 15 16 org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ 17 org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ 18 org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver 19 20 org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator 21 22 org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver 23 24 org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
Spring MVC之DispatcherServlet初始化