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)

The request processing workflow in Spring Web MVC (high level)

DispatcherServlet是一个实实在在的Servlet(它继承自HttpServlet基类),因此在Web应用程序中声明。您需要使用URL映射来映射希望DispatcherServlet去处理的请求。以下是Servlet 3.0+环境中的标准Java EE Servlet配置:

  1. public class MyWebApplicationInitializer implements WebApplicationInitializer {
  2. @Override
  3. public void onStartup(ServletContext container) {
  4. ServletRegistration.Dynamic registration = container.addServlet("example", new DispatcherServlet());
  5. registration.setLoadOnStartup(1);
  6. registration.addMapping("/example/*");
  7. }
  8. }

在前面的示例中,以/example开头的所有请求都将由名为exampleDispatcherServlet实例处理。

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中的配置等价于上面基于代码的例子:

  1. <web-app>
  2. <servlet>
  3. <servlet-name>example</servlet-name>
  4. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  5. <load-on-startup>1</load-on-startup>
  6. </servlet>
  7. <servlet-mapping>
  8. <servlet-name>example</servlet-name>
  9. <url-pattern>/example/*</url-pattern>
  10. </servlet-mapping>
  11. </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

The request processing workflow in Spring Web MVC (high level)

初始化DispatcherServlet时,Spring MVC会在Web应用程序的WEB-INF目录中查找名为[servlet-name]-servlet.xml的文件,并且创建文件中定义的bean,覆盖在全局作用域中使用相同名称描述的bean的定义。

请考虑下面的DispatcherServletServlet配置(在web.xml文件中):

  1. <web-app>
  2. <servlet>
  3. <servlet-name>golfing</servlet-name>
  4. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  5. <load-on-startup>1</load-on-startup>
  6. </servlet>
  7. <servlet-mapping>
  8. <servlet-name>golfing</servlet-name>
  9. <url-pattern>/golfing/*</url-pattern>
  10. </servlet-mapping>
  11. </web-app>

使用上述Servlet配置,应用程序中需要有一个名为/WEB-INF/golfing-servlet.xml的文件;该文件中要包含所有Spring Web MVC相关的组件(bean)。可以通过Servlet初始化参数更改此配置文件的确切位置(详细信息请参阅下文)。

对单一DispatcherServlet的场景,也可能只有一个根上下文。

Figure 22.3. Single root context in Spring Web MVC

The request processing workflow in Spring Web MVC (high level)

这可以通过设置一个空的ContextConfigLocation servlet init参数进行配置,如下所示:

  1. <web-app>
  2. <context-param>
  3. <param-name>contextConfigLocation</param-name>
  4. <param-value>/WEB-INF/root-context.xml</param-value>
  5. </context-param>
  6. <servlet>
  7. <servlet-name>dispatcher</servlet-name>
  8. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  9. <init-param>
  10. <param-name>contextConfigLocation</param-name>
  11. <param-value></param-value>
  12. </init-param>
  13. <load-on-startup>1</load-on-startup>
  14. </servlet>
  15. <servlet-mapping>
  16. <servlet-name>dispatcher</servlet-name>
  17. <url-pattern>/*</url-pattern>
  18. </servlet-mapping>
  19. <listener>
  20. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  21. </listener>
  22. </web-app>

WebApplicationContext是普通ApplicationContext的一个扩展,它具有Web应用程序所需的一些额外功能。它与普通的ApplicationContext的不同之处在于它能够解析主题(见22.9节“使用主题”),还在于它知道它与哪个Servlet相关联(有一个到ServletContext的链接)。WebApplicationContext绑定在ServletContext中,并且如果需要访问WebApplicationContext,可以通过使用RequestContextUtils类的静态方法随时找到它。

请注意,我们可以通过基于Java的配置达到同样的目的:

  1. public class GolfingWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  2. @Override
  3. protected Class<?>[] getRootConfigClasses() {
  4. // GolfingAppConfig defines beans that would be in root-context.xml
  5. return new Class[] { GolfingAppConfig.class };
  6. }
  7. @Override
  8. protected Class<?>[] getServletConfigClasses() {
  9. // GolfingWebConfig defines beans that would be in golfing-servlet.xml
  10. return new Class[] { GolfingWebConfig.class };
  11. }
  12. @Override
  13. protected String[] getServletMappings() {
  14. return new String[] { "/golfing/*" };
  15. }
  16. }