22.2 DispatcherServlet
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 {
@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提供的接口,用于确保基于代码的配置能被检测到并自动用于初始化任何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的定义。
请考虑下面的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的场景,也可能只有一个根上下文。
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 {
@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/*" };
}
}