22.2 DispatcherServlet
和许多其他的Web MVC框架一样,Spring的Web MVC框架是请求驱动的,围绕一个向控制器分派请求的中央Servlet设计,并提供了其他有助于Web应用程序开发的功能。但是,Spring的DispatcherServlet不仅仅如此,它和Spring的IoC容器完全集成,因而您可以使用Spring的每一个功能。
Spring Web MVC中DispatcherServlet的请求处理工作流程如下图所示。精通模式的读者会看出DispatcherServlet是“前端控制器”设计模式的一种表述(这是Spring Web MVC与其他许多领先的Web框架共享的一种模式)。
Figure 22.1. The request processing workflow in Spring Web MVC (high level)

DispatcherServlet是一个实实在在的Servlet(它继承自HttpServlet基类),因此在Web应用程序中声明。您需要使用URL映射来映射希望DispatcherServlet去处理的请求。以下是Servlet 3.0+环境中的标准Java EE Servlet配置:
public class MyWebApplicationInitializer implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext container) {ServletRegistration.Dynamic registration = container.addServlet("example", new DispatcherServlet());registration.setLoadOnStartup(1);registration.addMapping("/example/*");}}
在前面的示例中,以/example开头的所有请求都将由名为example的DispatcherServlet实例处理。
WebApplicationInitializer是由Spring MVC提供的接口,用于确保基于代码的配置能被检测到并自动用于初始化任何Servlet 3容器。实现了该接口名为AbstractAnnotationConfigDispatcherServletInitializer的抽象基类通过简单地指定其servlet映射和列出配置类使得注册DispatcherServlet更加容易——这甚至是设置Spring MVC应用程序的推荐方式。详细信息请参阅基于代码的Servlet容器初始化。
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>
如7.15节“ApplicationContext的附加功能”中所述,Spring中的ApplicationContext实例可以限定作用域。在Web MVC框架中,每个DispatcherServlet都有自己的WebApplicationContext,它继承了所有已经在根WebApplicationContext中定义的bean。根WebApplicationContext应该包含全部的基础组件bean,这些bean应该在其他上下文中和Servlet实例之间共享。在特定于servlet的域中,这些被继承的bean可以被覆盖,并且您可以为给定的Servlet实例定义新的特定于指定作用域的bean。
Figure 22.2. Typical context hierarchy in Spring Web MVC

初始化DispatcherServlet时,Spring MVC会在Web应用程序的WEB-INF目录中查找名为[servlet-name]-servlet.xml的文件,并且创建文件中定义的bean,覆盖在全局作用域中使用相同名称描述的bean的定义。
请考虑下面的DispatcherServletServlet配置(在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的场景,也可能只有一个根上下文。
Figure 22.3. Single root context in 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的不同之处在于它能够解析主题(见22.9节“使用主题”),还在于它知道它与哪个Servlet相关联(有一个到ServletContext的链接)。WebApplicationContext绑定在ServletContext中,并且如果需要访问WebApplicationContext,可以通过使用RequestContextUtils类的静态方法随时找到它。
请注意,我们可以通过基于Java的配置达到同样的目的:
public class GolfingWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {@Overrideprotected Class<?>[] getRootConfigClasses() {// GolfingAppConfig defines beans that would be in root-context.xmlreturn new Class[] { GolfingAppConfig.class };}@Overrideprotected Class<?>[] getServletConfigClasses() {// GolfingWebConfig defines beans that would be in golfing-servlet.xmlreturn new Class[] { GolfingWebConfig.class };}@Overrideprotected String[] getServletMappings() {return new String[] { "/golfing/*" };}}
