1 概述:Spring Web DispatcherServlet
DispatcherServlet 简介
org.springframework.web.servlet.DispatcherServlet
是一个Servlet
,它接收所有的HTTP
请求,并根据请求的信息将其分发给相应的处理器(Handler
)进行处理。- 它是
Spring MVC
架构模式中的关键部分,将请求处理逻辑与实际的业务逻辑解耦,使得代码结构更加清晰和易于维护。
2 DispatcherServlet 的初始化
Step1 Servlet 容器启动
- 当 Web 应用启动时,
Servlet
容器(如 Tomcat)会加载和初始化所有配置的Servlet
。 - 对于
DispatcherServlet
,它的初始化过程在这个阶段开始。
Step2 读取配置
Step2.1 Servlet 初始化参数
DispatcherServlet
可以从web.xm
l(传统方式)或者基于Java
的配置(如使用@WebServlet
注解)中获取初始化参数。
这些参数可以指定配置文件的位置、Spring 应用上下文的名称等信息。
例如,在传统的 web.xml 配置中,可以如下设置:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
- 这里指定了
contextConfigLocation
参数,告诉DispatcherServlet
去哪里寻找Spring MVC
的配置文件。
load-on-startup
参数的值大于0
,表示在容器启动时就初始化该Servlet
。
Step2.2 加载 Spring 配置文件
- 根据配置的
contextConfigLocation
参数,DispatcherServlet
会加载Spring
的配置文件。
在这个配置文件中,可以定义各种 Spring 组件,如视图解析器、处理器映射器、处理器适配器等。
这些组件对于后续的请求处理至关重要。
Step3 创建 Web 应用上下文
根上下文与子上下文
DispatcherServlet
会创建自己的Web
应用上下文(通常是WebApplicationContext
类型)。
这个上下文是整个
Spring MVC
应用的核心。
在一些复杂的应用中,可能还存在根上下文(由ContextLoaderListener
创建),而DispatcherServlet
的上下文是根上下文的子上下文。
组件扫描与初始化
- 在创建
Web
应用上下文的过程中,会根据配置进行组件扫描。 - 它会查找并实例化所有配置的 Spring 组件,包括控制器(Controller)、服务(Service)等相关类。
- 同时,会初始化在配置文件中定义的各种 bean,如视图解析器(ViewResolver)会被创建并配置好相应的视图解析策略。
深入分析:Spring Web DispatcherServlet 注册 Serlvet 的过程
Servlet 的注册: 传统 Servlet vs. Servlet 3
-
传统的
Servlet
注册是配置在/WEB-INF/web.xml
下,在容器启动的时候注册Servlet
。 -
Servlet 3
规范为我们又提供了一种更加方便的注册方法————容器启动的时候扫描jar包,找到jar包下一个为如下文件路径的文件。
META-INF/services/javax.servlet.ServletContainerInitializer
该文件的内容必须是一个实现了javax.servlet.ServletContainerInitializer
接口的实现类,该接口下有一个方法会自动被调用。
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException
其中第一个参数是一个Set
,当该实现类上有注解@HandlesTypes
,注解的value
属性是一个Class[]
,这个数组及其子类(或实现类)会被注入到webAppInitializerClasses
参数中。
Spring Web DispatcherServlet 注册过程
下面我们看看Spring
是如何利用Servlet 3
这种方式完成DispatcherServlet
的注册。
ServletContainerInitializer
- 在
spring-web
模块下,META-INF/services/javax.servlet.ServletContainerInitializer
文件中的内容为:
org.springframework.web.SpringServletContainerInitializer
SpringServletContainerInitializer
- 该类实现了
ServletContainerInitializer
接口,并标有@HandlesTypes
注解。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
@HandlesTypes({WebApplicationInitializer.class}) // 关键注解 : HandlesTypes
public class SpringServletContainerInitializer implements ServletContainerInitializer { // 关键接口 : 实现了 Servlet 3 规范的 ServletContainerInitializer 接口
public SpringServletContainerInitializer() {
}
//关键方法: onStartup
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList();
Iterator var4;
if (webAppInitializerClasses != null) {
var4 = webAppInitializerClasses.iterator();
while(var4.hasNext()) {
Class<?> waiClass = (Class)var4.next();
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());
} catch (Throwable var7) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
} else {
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
var4 = initializers.iterator();
while(var4.hasNext()) {
WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
initializer.onStartup(servletContext);
}
}
}
}
onStartup
方法:
- 会将
WebApplicationInitializer
的实现类实例放到List
中排序,依次调用onStartup()
方法。Spring
为我们提供了一个WebApplicationInitializer
的抽象实现类AbstractAnnotationConfigDispatcherServletInitializer
,通常我们只需要继承此类来完成DispatcherServlet
与spring context
的注册。
AbstractDispatcherServletInitializer#onStartup
AbstractAnnotationConfigDispatcherServletInitializer
的父类AbstractDispatcherServletInitializer
覆盖了onStartup()
方法:
//org.springframework.web.servlet.support.AbstractDispatcherServletInitializer
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
registerDispatcherServlet(servletContext);
}
首先,调用父类的方法完成root WebApplicationContext
的初始化;
然后,调用registerDispatcherServlet()
方法完成DispatcherServlet
的注册。
AbstractDispatcherServletInitializer#registerDispatcherServlet
//org.springframework.web.servlet.support.AbstractDispatcherServletInitializer
protected void registerDispatcherServlet(javax.servlet.ServletContext servletContext) {
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() must not return empty or null");
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext,
"createServletApplicationContext() did not return an application " +
"context for servlet [" + servletName + "]");
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
Assert.notNull(registration,
"Failed to register servlet with name '" + servletName + "'." +
"Check if there is another servlet registered under the same name.");
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
暂时只关注Servlet
的注册,Spring
容器相关的以后介绍,createDispatcherServlet()
方法创建了一个DispatcherServlet
实例,然后通过servletContext.addServlet()
方法完成DispatcherServlet
的注册。
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
return new DispatcherServlet(servletAppContext);
}
以上就是DispatcherServlet
的注册过程。
3 DispatcherServlet 的工作流程
Step1 接收请求
当一个 HTTP 请求到达 Servlet 容器时,容器会根据请求的 URL 将其路由到相应的 Servlet。对于匹配 DispatcherServlet 的请求(通常是通过 Servlet 映射配置),DispatcherServlet 开始处理这个请求。
Step2 请求处理准备
请求的解析与封装
- DispatcherServlet 首先会对请求进行解析,将 HTTP 请求中的信息(如请求方法、请求参数、请求头、请求路径等)封装到HttpServletRequest对象中。这个对象将在整个请求处理过程中传递和使用。
获取处理器映射器(HandlerMapping)
- DispatcherServlet 会从其初始化创建的 Web 应用上下文中获取处理器映射器。处理器映射器的作用是根据请求的信息(主要是 URL)找到处理该请求的处理器(Handler)。Spring 提供了多种类型的处理器映射器,如RequestMappingHandlerMapping等,它们通过不同的策略来确定处理器。
Step3 查找处理器
根据请求查找处理器
- 处理器映射器会根据请求的 URL、请求方法等信息在已经注册的处理器中查找匹配的处理器。例如,如果使用@RequestMapping注解来定义控制器方法的映射,处理器映射器会根据请求的 URL 模式和请求方法(如 GET、POST 等)来确定对应的@RequestMapping注解标注的方法。
返回处理器执行链(HandlerExecutionChain)
- 一旦找到匹配的处理器,处理器映射器会返回一个包含处理器和相关拦截器(Interceptor)的处理器执行链。拦截器可以在处理器执行前后执行一些额外的逻辑,如权限验证、日志记录等。
Step4 获取处理器适配器(HandlerAdapter)
选择合适的适配器
- DispatcherServlet 根据处理器的类型从 Web 应用上下文中获取合适的处理器适配器。不同类型的处理器(如基于方法的处理器、基于控制器类的处理器等)需要不同的适配器来执行。
例如,对于使用@RequestMapping注解的处理器方法,会使用RequestMappingHandlerAdapter。
调用处理器适配器执行处理器
- 处理器适配器负责调用处理器的具体方法,并将请求相关的参数传递给处理器。
在执行过程中,处理器(通常是控制器方法)会执行业务逻辑,可能涉及到调用服务层、数据访问层等,最终返回一个模型和视图(ModelAndView)对象或者其他类型的结果(如直接返回数据等情况)。
Step5 视图解析
获取视图解析器(ViewResolver)
- 如果处理器返回了一个ModelAndView对象,DispatcherServlet 会从 Web 应用上下文中获取视图解析器。视图解析器根据ModelAndView中指定的视图名称和其他相关信息来确定实际的视图实现。
解析视图
- 不同的视图解析器有不同的解析策略。例如,InternalResourceViewResolver可以将视图名称解析为 JSP 文件的路径。视图解析器会返回一个View对象,这个对象负责渲染最终的视图。
Step6 视图渲染与响应返回
渲染视图
- View对象会根据模型数据(如果有)和请求信息对视图进行渲染。如果是 JSP 视图,会将模型数据填充到 JSP 页面中,然后生成最终的 HTML 内容。
返回响应
- 渲染后的视图内容会被封装到HttpServletResponse对象中,并通过 Servlet 容器返回给客户端,完成整个请求处理流程。
小结
- 总之,DispatcherServlet 在 Spring MVC 应用中起着至关重要的作用,它的初始化过程构建了整个请求处理的基础架构,而其工作流程则有条不紊地处理每个请求,将用户的请求转化为最终的响应,为开发高效、可维护的 Web 应用提供了有力的支持。
Y DispatcherServlet
完整源码
spring-webmvc
:5.2.15.RELEASE
package/import
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.log.LogFormatUtils;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.ui.context.ThemeSource;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.util.NestedServletException;
import org.springframework.web.util.WebUtils;
DispatcherServlet extends FrameworkServlet、属性
public class DispatcherServlet extends FrameworkServlet {
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";
public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";
public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP";
public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER";
public static final String EXCEPTION_ATTRIBUTE = DispatcherServlet.class.getName() + ".EXCEPTION";
public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
private static final String DEFAULT_STRATEGIES_PREFIX = "org.springframework.web.servlet";
protected static final Log pageNotFoundLogger = LogFactory.getLog("org.springframework.web.servlet.PageNotFound");
private static final Properties defaultStrategies;
private boolean detectAllHandlerMappings = true;
private boolean detectAllHandlerAdapters = true;
private boolean detectAllHandlerExceptionResolvers = true;
private boolean detectAllViewResolvers = true;
private boolean throwExceptionIfNoHandlerFound = false;
private boolean cleanupAfterInclude = true;
@Nullable
private MultipartResolver multipartResolver;
@Nullable
private LocaleResolver localeResolver;
@Nullable
private ThemeResolver themeResolver;
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
private List<HandlerAdapter> handlerAdapters;
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
@Nullable
private FlashMapManager flashMapManager;
@Nullable
private List<ViewResolver> viewResolvers;
构造器
public DispatcherServlet() {
this.setDispatchOptionsRequest(true);
}
public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
this.setDispatchOptionsRequest(true);
}
方法/代码块
setDetectAllHandlerMappings/setDetectAllHandlerAdapters/setDetectAllHandlerExceptionResolvers/setDetectAllViewResolvers/setThrowExceptionIfNoHandlerFound/setCleanupAfterInclude
public void setDetectAllHandlerMappings(boolean detectAllHandlerMappings) {
this.detectAllHandlerMappings = detectAllHandlerMappings;
}
public void setDetectAllHandlerAdapters(boolean detectAllHandlerAdapters) {
this.detectAllHandlerAdapters = detectAllHandlerAdapters;
}
public void setDetectAllHandlerExceptionResolvers(boolean detectAllHandlerExceptionResolvers) {
this.detectAllHandlerExceptionResolvers = detectAllHandlerExceptionResolvers;
}
public void setDetectAllViewResolvers(boolean detectAllViewResolvers) {
this.detectAllViewResolvers = detectAllViewResolvers;
}
public void setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound) {
this.throwExceptionIfNoHandlerFound = throwExceptionIfNoHandlerFound;
}
public void setCleanupAfterInclude(boolean cleanupAfterInclude) {
this.cleanupAfterInclude = cleanupAfterInclude;
}
onRefresh
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
initStrategies/initMultipartResolver/initLocaleResolver/initThemeResolver
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
private void initMultipartResolver(ApplicationContext context) {
try {
this.multipartResolver = (MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Detected " + this.multipartResolver);
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
}
} catch (NoSuchBeanDefinitionException var3) {
this.multipartResolver = null;
if (this.logger.isTraceEnabled()) {
this.logger.trace("No MultipartResolver 'multipartResolver' declared");
}
}
}
private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = (LocaleResolver)context.getBean("localeResolver", LocaleResolver.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Detected " + this.localeResolver);
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
}
} catch (NoSuchBeanDefinitionException var3) {
this.localeResolver = (LocaleResolver)this.getDefaultStrategy(context, LocaleResolver.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No LocaleResolver 'localeResolver': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
}
}
}
private void initThemeResolver(ApplicationContext context) {
try {
this.themeResolver = (ThemeResolver)context.getBean("themeResolver", ThemeResolver.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Detected " + this.themeResolver);
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());
}
} catch (NoSuchBeanDefinitionException var3) {
this.themeResolver = (ThemeResolver)this.getDefaultStrategy(context, ThemeResolver.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No ThemeResolver 'themeResolver': using default [" + this.themeResolver.getClass().getSimpleName() + "]");
}
}
}
initHandlerMappings/initHandlerAdapters
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException var3) {
}
}
if (this.handlerMappings == null) {
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
}
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
} else {
try {
HandlerAdapter ha = (HandlerAdapter)context.getBean("handlerAdapter", HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
} catch (NoSuchBeanDefinitionException var3) {
}
}
if (this.handlerAdapters == null) {
this.handlerAdapters = this.getDefaultStrategies(context, HandlerAdapter.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No HandlerAdapters declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
}
initHandlerExceptionResolvers
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
} else {
try {
HandlerExceptionResolver her = (HandlerExceptionResolver)context.getBean("handlerExceptionResolver", HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
} catch (NoSuchBeanDefinitionException var3) {
}
}
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = this.getDefaultStrategies(context, HandlerExceptionResolver.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No HandlerExceptionResolvers declared in servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
}
initRequestToViewNameTranslator
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
this.viewNameTranslator = (RequestToViewNameTranslator)context.getBean("viewNameTranslator", RequestToViewNameTranslator.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Detected " + this.viewNameTranslator);
}
} catch (NoSuchBeanDefinitionException var3) {
this.viewNameTranslator = (RequestToViewNameTranslator)this.getDefaultStrategy(context, RequestToViewNameTranslator.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No RequestToViewNameTranslator 'viewNameTranslator': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
}
}
}
initViewResolvers
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
Map<String, ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
} else {
try {
ViewResolver vr = (ViewResolver)context.getBean("viewResolver", ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
} catch (NoSuchBeanDefinitionException var3) {
}
}
if (this.viewResolvers == null) {
this.viewResolvers = this.getDefaultStrategies(context, ViewResolver.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No ViewResolvers declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
}
initFlashMapManager
private void initFlashMapManager(ApplicationContext context) {
try {
this.flashMapManager = (FlashMapManager)context.getBean("flashMapManager", FlashMapManager.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Detected " + this.flashMapManager);
}
} catch (NoSuchBeanDefinitionException var3) {
this.flashMapManager = (FlashMapManager)this.getDefaultStrategy(context, FlashMapManager.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No FlashMapManager 'flashMapManager': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");
}
}
}
getThemeSource/getMultipartResolver/getHandlerMappings
@Nullable
public final ThemeSource getThemeSource() {
return this.getWebApplicationContext() instanceof ThemeSource ? (ThemeSource)this.getWebApplicationContext() : null;
}
@Nullable
public final MultipartResolver getMultipartResolver() {
return this.multipartResolver;
}
@Nullable
public final List<HandlerMapping> getHandlerMappings() {
return this.handlerMappings != null ? Collections.unmodifiableList(this.handlerMappings) : null;
}
getDefaultStrategy/getDefaultStrategies/createDefaultStrategy
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
List<T> strategies = this.getDefaultStrategies(context, strategyInterface);
if (strategies.size() != 1) {
throw new BeanInitializationException("DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
} else {
return strategies.get(0);
}
}
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value == null) {
return new LinkedList();
} else {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList(classNames.length);
String[] var7 = classNames;
int var8 = classNames.length;
for(int var9 = 0; var9 < var8; ++var9) {
String className = var7[var9];
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = this.createDefaultStrategy(context, clazz);
strategies.add(strategy);
} catch (ClassNotFoundException var13) {
throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var13);
} catch (LinkageError var14) {
throw new BeanInitializationException("Unresolvable class definition for DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var14);
}
}
return strategies;
}
}
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
return context.getAutowireCapableBeanFactory().createBean(clazz);
}
doService
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames();
label95:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label95;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
logRequest
private void logRequest(HttpServletRequest request) {
LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
String params;
if (this.isEnableLoggingRequestDetails()) {
params = (String)request.getParameterMap().entrySet().stream().map((entry) -> {
return (String)entry.getKey() + ":" + Arrays.toString((Object[])entry.getValue());
}).collect(Collectors.joining(", "));
} else {
params = request.getParameterMap().isEmpty() ? "" : "masked";
}
String queryString = request.getQueryString();
String queryClause = StringUtils.hasLength(queryString) ? "?" + queryString : "";
String dispatchType = !request.getDispatcherType().equals(DispatcherType.REQUEST) ? "\"" + request.getDispatcherType().name() + "\" dispatch for " : "";
String message = dispatchType + request.getMethod() + " \"" + getRequestUri(request) + queryClause + "\", parameters={" + params + "}";
if (traceOn) {
List<String> values = Collections.list(request.getHeaderNames());
String headers = values.size() > 0 ? "masked" : "";
if (this.isEnableLoggingRequestDetails()) {
headers = (String)values.stream().map((name) -> {
return name + ":" + Collections.list(request.getHeaders(name));
}).collect(Collectors.joining(", "));
}
return message + ", headers={" + headers + "} in DispatcherServlet '" + this.getServletName() + "'";
} else {
return message;
}
});
}
doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
applyDefaultViewName
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
if (mv != null && !mv.hasView()) {
String defaultViewName = this.getDefaultViewName(request);
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}
processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
if (mv != null && !mv.wasCleared()) {
this.render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("No view rendering, null ModelAndView returned.");
}
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
buildLocaleContext
protected LocaleContext buildLocaleContext(HttpServletRequest request) {
LocaleResolver lr = this.localeResolver;
return lr instanceof LocaleContextResolver ? ((LocaleContextResolver)lr).resolveLocaleContext(request) : () -> {
return lr != null ? lr.resolveLocale(request) : request.getLocale();
};
}
checkMultipart
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
if (request.getDispatcherType().equals(DispatcherType.REQUEST)) {
this.logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
}
} else if (this.hasMultipartException(request)) {
this.logger.debug("Multipart resolution previously failed for current request - skipping re-resolution for undisturbed error rendering");
} else {
try {
return this.multipartResolver.resolveMultipart(request);
} catch (MultipartException var3) {
if (request.getAttribute("javax.servlet.error.exception") == null) {
throw var3;
}
}
this.logger.debug("Multipart resolution failed for error dispatch", var3);
}
}
return request;
}
hasMultipartException
private boolean hasMultipartException(HttpServletRequest request) {
for(Throwable error = (Throwable)request.getAttribute("javax.servlet.error.exception"); error != null; error = error.getCause()) {
if (error instanceof MultipartException) {
return true;
}
}
return false;
}
cleanupMultipart
protected void cleanupMultipart(HttpServletRequest request) {
if (this.multipartResolver != null) {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
if (multipartRequest != null) {
this.multipartResolver.cleanupMultipart(multipartRequest);
}
}
}
getHandler
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
noHandlerFound
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (pageNotFoundLogger.isWarnEnabled()) {
pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
}
if (this.throwExceptionIfNoHandlerFound) {
throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request), (new ServletServerHttpRequest(request)).getHeaders());
} else {
response.sendError(404);
}
}
getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
processHandlerException
@Nullable
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception {
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
Iterator var6 = this.handlerExceptionResolvers.iterator();
while(var6.hasNext()) {
HandlerExceptionResolver resolver = (HandlerExceptionResolver)var6.next();
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
if (exMv != null) {
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
} else {
if (!exMv.hasView()) {
String defaultViewName = this.getDefaultViewName(request);
if (defaultViewName != null) {
exMv.setViewName(defaultViewName);
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Using resolved error view: " + exMv, ex);
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Using resolved error view: " + exMv);
}
WebUtils.exposeErrorRequestAttributes(request, ex, this.getServletName());
return exMv;
}
} else {
throw ex;
}
}
render
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
response.setLocale(locale);
String viewName = mv.getViewName();
View view;
if (viewName != null) {
view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
}
} else {
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
} catch (Exception var8) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "]", var8);
}
throw var8;
}
}
getDefaultViewName/resolveViewName
@Nullable
protected String getDefaultViewName(HttpServletRequest request) throws Exception {
return this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null;
}
@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
Iterator var5 = this.viewResolvers.iterator();
while(var5.hasNext()) {
ViewResolver viewResolver = (ViewResolver)var5.next();
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
triggerAfterCompletion
private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, ex);
}
throw ex;
}
restoreAttributesAfterInclude
private void restoreAttributesAfterInclude(HttpServletRequest request, Map<?, ?> attributesSnapshot) {
Set<String> attrsToCheck = new HashSet();
Enumeration attrNames = request.getAttributeNames();
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
attrsToCheck.addAll(attributesSnapshot.keySet());
Iterator var8 = attrsToCheck.iterator();
while(var8.hasNext()) {
String attrName = (String)var8.next();
Object attrValue = attributesSnapshot.get(attrName);
if (attrValue == null) {
request.removeAttribute(attrName);
} else if (attrValue != request.getAttribute(attrName)) {
request.setAttribute(attrName, attrValue);
}
}
return;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attrsToCheck.add(attrName);
}
}
getRequestUri
private static String getRequestUri(HttpServletRequest request) {
String uri = (String)request.getAttribute("javax.servlet.include.request_uri");
if (uri == null) {
uri = request.getRequestURI();
}
return uri;
}
static 块
static {
try {
ClassPathResource resource = new ClassPathResource("DispatcherServlet.properties", DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
} catch (IOException var1) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + var1.getMessage());
}
}
}
X 参考文献
- 01、Spring源码分析 - 01-DispatcherServlet注册过程 - DDKK.COM 弟弟快看
- Spring DispatcherServlet 详解 - CSDN
- spring-framework
标签:Web,null,Java,Spring,request,context,import,logger,DispatcherServlet From: https://www.cnblogs.com/johnnyzen/p/18471215