参考:https://docs.spring.io/spring/docs/4.3.20.RELEASE/spring-framework-reference/htmlsingle/#mvc-servlet
Spring的Web MVC框架与许多其他Web MVC框架一样,是基于请求驱动的,围绕中央Servlet设计,该Servlet将请求分派给控制器并提供便于Web应用程序开发的其他功能。 然而,Spring的DispatcherServlet不仅如此,它与Spring IoC容器完全集成,因此允许使用Spring拥有的所有功能。
Spring Web MVC DispatcherServlet的请求处理工作流程如下图所示。 DispatcherServlet是“Front Controller”(前端控制器)设计模式的表达(这是Spring Web MVC与许多其他领先的Web框架共享的模式)。
Spring Web MVC中的请求处理工作流程(高级)图:
DispatcherServlet是一个实际的Servlet(它继承自HttpServlet基类),因此在Web应用程序中声明。 需要使用URL映射来映射希望DispatcherServlet处理的请求。 以下是Servlet 3.0+环境中的标准Java EE Servlet配置:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
ServletRegistration.Dynamic registration = container.addServlet("example", new DispatcherServlet());
registration.setLoadOnStartup(1);
registration.addMapping("/example/*");
}
}
在上面的示例中,所有以/example开头的请求都将由名为example的DispatcherServlet实例处理。
WebApplicationInitializer是Spring MVC提供的一个接口,可确保检测到基于代码的配置并自动用于初始化任何Servlet3容器。 这个名为AbstractAnnotationConfigDispatcherServletInitializer的接口的抽象基类实现使得通过简单地指定其servlet映射和列出配置类来更容易地注册DispatcherServlet --- 它是建立Spring MVC应用程序的推荐方法。
DispatcherServlet是一个实际的Servlet(它继承自HttpServlet基类),因此在Web应用程序的web.xml中声明。 您需要使用同一web.xml文件中的URL映射来映射您希望DispatcherServlet处理的请求。 这是标准的Java EE Servlet配置; 以下示例显示了这样的DispatcherServlet声明和映射:
使用web.xml实现与上面示例中类似的功能:
<web-app>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>/example/*</url-pattern>
</servlet-mapping>
</web-app>
Spring中的ApplicationContext实例可以被作用域化。 在Web MVC框架中,每个DispatcherServlet都有自己的WebApplicationContext,它继承了根WebApplicationContext中已定义的所有bean。 根WebApplicationContext应包含在其他上下文和Servlet实例之间共享的所有基础结构bean。 可以在特定servlet的作用域中重写这些继承的bean,并且可以为给定的Servlet实例定义新的作用域特定的bean。
Spring Web MVC中的典型上下文层次结构图:
在初始化DispatcherServlet时,Spring MVC在Web应用程序的WEB-INF目录中查找名为[servlet-name]-servlet.xml的文件,并创建定义的bean,在全局范围内覆盖使用相同名称定义的任何bean的定义。
请考虑以下DispatcherServlet Servlet配置(在web.xml文件中):
<web-app>
<servlet>
<servlet-name>golfing</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>golfing</servlet-name>
<url-pattern>/golfing/*</url-pattern>
</servlet-mapping>
</web-app>
使用上面的Servlet配置,需要在应用程序中有一个名为/WEB-INF/golfing-servlet.xml的文件; 此文件将包含所有Spring Web MVC特定组件(bean)。可以通过Servlet初始化参数更改此配置文件的位置。
对于单个DispatcherServlet方案,也可以只有一个根上下文。
Spring Web MVC中的单个根上下文图:
这可以通过设置一个空的contextConfigLocation servlet init参数来配置,如下所示:
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
WebApplicationContext是普通ApplicationContext的扩展,它具有Web应用程序所需的一些额外功能。 它与普通的ApplicationContext的不同之处在于它能够解析主题,并且它知道它与哪个Servlet相关联(通过指向ServletContext的链接)。 WebApplicationContext绑定在ServletContext中,通过在RequestContextUtils类上使用静态方法,如果需要访问WebApplicationContext,则始终可以查找它。
可以使用基于java的配置实现相同的功能:
public class GolfingWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
// GolfingAppConfig defines beans that would be in root-context.xml
return new Class<?>[] { GolfingAppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
// GolfingWebConfig defines beans that would be in golfing-servlet.xml
return new Class<?>[] { GolfingWebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/golfing/*" };
}
}
1. WebApplicationContext中的特殊Bean类型
Spring DispatcherServlet使用特殊bean来处理请求并呈现适当的视图。 这些bean是Spring MVC的一部分。 您可以通过在WebApplicationContext中简单地配置其中一个或多个来选择要使用的特殊bean。 但是,您最初不需要这样做,因为如果您不配置任何默认bean,Spring MVC会维护一个默认Bean列表。 更多内容将在下一节中介绍。 首先看下表列出了DispatcherServlet所依赖的特殊bean类型。
Bean type | Explanation |
---|---|
根据某些标准将传入请求映射到处理器以及预处理器和后置处理器列表(处理器拦截器),其详细信息因HandlerMapping实现而异。 最流行的实现支持带注解的控制器,但也存在其他实现。 | |
HandlerAdapter | 无论实际调用哪个处理器,都可以帮助DispatcherServlet调用映射到请求的处理器。 例如,调用带注解的控制器需要解析各种注解。 因此,HandlerAdapter的主要目的是保护DispatcherServlet不受此类细节的影响。 |
将异常映射到视图,也允许更复杂的异常处理代码。 | |
将基于逻辑字符串的视图名称解析为实际的视图类型。 | |
解析客户端正在使用的区域设置以及可能的时区,以便能够提供国际化视图 | |
解析Web应用程序可以使用的主题,例如,提供个性化布局 | |
解析多部件请求,例如支持从HTML表单处理文件上传。 | |
存储和检索“输入”和“输出”FlashMap,可用于将属性从一个请求传递到另一个请求,通常是通过重定向。 |
2. 默认的DispatcherServlet配置
DispatcherServlet维护了一个默认使用的实现列表。此信息保存在org.springframework.web.servlet包中的DispatcherServlet.properties文件中。
所有特殊bean都有一些合理的默认值。虽然需要定制这些bean提供的一个或多个属性。例如,将InternalResourceViewResolver设置其前缀属性配置为视图文件的父位置是很常见的。
一旦在WebApplicationContext中配置了一个特殊的bean(如InternalResourceViewResolver),就可以有效地覆盖那些特殊bean类型已经使用的默认实现列表。例如,如果配置InternalResourceViewResolver,则会忽略ViewResolver实现的默认列表。
3. DispatcherServlet处理流程
在设置DispatcherServlet后,向该DispatcherServlet发出请求后开始处理请求,如下所示:
- 在WebApplicationContext中搜索并绑定在请求中,作为控制器和进程中的其他元素可以使用的属性。它默认绑定在key为DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE下。
- 语言环境解析器绑定到请求,以使进程中的元素能够解析处理请求时使用的语言环境(展示视图,准备数据等)。如果不需要区域设置解析,则不需要它。
- 主题解析器绑定到请求,以允许视图等元素确定要使用的主题。如果不使用主题,则可以忽略它。
- 如果指定了多部件文件解析器,则会检查请求的多部件;如果找到多部件,请求将被包装在MultipartHttpServletRequest中,以供进程中的其他元素进一步处理。
- 搜索适当的处理器。如果找到处理器,则执行与处理器(拦截器【预处理器、后置处理器】和控制器)关联的执行链以准备模型或展示。
- 如果返回模型,则展示视图。如果没有返回模型(可能是由于拦截器【预处理器、后置处理器】拦截请求,可能是出于安全原因),则不会展示任何视图,因为该请求可能已经完成。
在WebApplicationContext中声明的处理器异常解析器会捕获在处理请求期间引发的异常。 使用这些异常解析器可以定义自定义行为以解决异常。
Spring DispatcherServlet还支持返回最后修改日期,如Servlet API所指定。 确定特定请求的最后修改日期的过程很简单:DispatcherServlet查找适当的处理器映射并测试找到的处理器是否实现LastModified接口。 如果是这样,LastModified接口的long getLastModified(request)方法的值将返回给客户端。
可以通过将Servlet初始化参数(init-param元素)添加到web.xml文件中的Servlet声明来自定义各个DispatcherServlet实例。 有关支持的参数列表,请参阅下表。
参数 | 说明 |
---|---|
| 实现WebApplicationContext的类,它实例化此Servlet使用的上下文。 默认情况下,使用XmlWebApplicationContext。 |
| 传递给上下文实例(由contextClass指定)的字符串,用于指示可以找到上下文的位置。 该字符串可能包含多个字符串(使用逗号作为分隔符)以支持多个上下文。 如果多个上下文位置的bean定义了两次,则最新位置优先。 |
| WebApplicationContext的命名空间。 默认为[servlet-name]-servlet。 |