原文: https://howtodoinjava.com/spring5/webmvc/spring-dispatcherservlet-tutorial/

了解 Spring 的DispatcherServlet类,其职责以及如何使用示例进行配置。

1. 什么是 Spring DispatcherServlet

DispatcherServlet充当基于 Spring 的 Web 应用程序的前控制器。 它提供了一种用于请求处理的机制,其中实际工作由可配置的委托组件执行。 它继承自javax.servlet.http.HttpServlet,通常在web.xml文件中进行配置。

Web 应用程序可以定义任意数量的DispatcherServlet实例。 每个 servlet 将在其自己的名称空间中运行,并使用映射,处理器等加载其自己的应用程序上下文。只有ContextLoaderListener加载的根应用程序上下文(如果有)将被共享。 在大多数情况下,应用程序仅具有上下文根 URL (/)的单个DispatcherServlet,即,到达该域的所有请求都将由该域处理。

DispatcherServlet使用 Spring 配置类发现请求映射,视图解析,异常处理等所需的委托组件。

2. 如何使用WebApplicationContext

让我们了解调度程序 servlet 在内部如何工作? 在基于 Spring 的应用程序中,我们的应用程序对象位于对象容器中。 该容器创建对象和对象之间的关联,并管理它们的完整生命周期。 这些容器对象称为 Spring 管理的 Bean(或简称为 Bean),在 Spring 世界中,该容器称为应用程序上下文(通过类ApplicationContext)。

WebApplicationContext是普通ApplicationContext的扩展。 它是网络感知的ApplicationContext,即它具有 Servlet 上下文信息。 加载DispatcherServlet后,它将查找WebApplicationContext的 bean 配置文件并对其进行初始化。

通过访问 Servlet 上下文,任何实现ServletConextAware接口的 spring bean – 都可以访问ServletContext实例并用它做很多事情。 例如,它可以获取上下文初始化参数,获取上下文根信息以及获取 Web 应用程序文件夹内的资源位置。

3. DispatcherServlet XML 配置

让我们看看典型的DispatcherServlet声明和初始化的样子。

web.xml

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

在上面的代码中,dispatcher-servlet-context.xml文件将包含所有可用于DispatcherServlet的 bean 定义和关联。 这些 bean 定义将覆盖在全局范围内用相同名称定义的任何 bean 的定义。 例如

applicationContext.xml

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://www.springframework.org/schema/beans
  4. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  5. <bean id="viewResolver"
  6. class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
  7. <property name="prefix">
  8. <value>/WEB-INF/views/</value>
  9. </property>
  10. <property name="suffix">
  11. <value>.jsp</value>
  12. </property>
  13. </bean>
  14. </beans>

4. DispatcherServlet Java 配置

从 Servlet 3.0 开始,除了web.xml文件中的声明性配置外,还可以通过实现或扩展 Spring 提供的这三个支持类之一来以编程方式配置DispatcherServlet

4.1. WebAppInitializer示例

在下面的类中,WebApplicationInitializer确保SpringServletContainerInitializer检测到类ApplicationInitializer(它本身会自动运行),并用于初始化任何 Servlet 3 容器。

spring boot DispatcherServlet映射的示例。

ApplicationInitializer.java

  1. public class ApplicationInitializer implements WebApplicationInitializer
  2. {
  3. @Override
  4. public void onStartup(ServletContext servletContext) throws ServletException
  5. {
  6. XmlWebApplicationContext appContext = new XmlWebApplicationContext();
  7. appContext.setConfigLocation("/WEB-INF/dispatcher-servlet-context.xml");
  8. ServletRegistration.Dynamic registration = servletContext
  9. .addServlet("rootDispatcher", new DispatcherServlet(appContext));
  10. registration.setLoadOnStartup(1);
  11. registration.addMapping("/");
  12. }
  13. }

4.2. 完整的基于 Java 的初始化

ApplicationInitializer.java

  1. public class ApplicationInitializer implements WebApplicationInitializer
  2. {
  3. @Override
  4. public void onStartup(ServletContext container)
  5. {
  6. // Create the 'root' Spring application context
  7. AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
  8. rootContext.register(AppConfig.class);
  9. // Manage the lifecycle of the root application context
  10. container.addListener(new ContextLoaderListener(rootContext));
  11. // Create the dispatcher servlet's Spring application context
  12. AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
  13. dispatcherContext.register(DispatcherConfig.class);
  14. ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher",
  15. new DispatcherServlet(dispatcherContext));
  16. dispatcher.setLoadOnStartup(1);
  17. dispatcher.addMapping("/");
  18. }
  19. }

在上面的代码中,AppConfigDispatcherConfig类定义将在 Web 应用程序上下文中的 spring 托管 bean。

4.3. AbstractDispatcherServletInitializer示例

这是在 Servlet 上下文中注册DispatcherServletWebApplicationInitializer实现的基类。

ApplicationInitializer.java

  1. public class ApplicationInitializer extends AbstractDispatcherServletInitializer {
  2. @Override
  3. protected WebApplicationContext createRootApplicationContext() {
  4. return null;
  5. }
  6. @Override
  7. protected WebApplicationContext createServletApplicationContext() {
  8. XmlWebApplicationContext cxt = new XmlWebApplicationContext();
  9. cxt.setConfigLocation("/WEB-INF/dispatcher-servlet-context.xml");
  10. return cxt;
  11. }
  12. @Override
  13. protected String[] getServletMappings() {
  14. return new String[] { "/" };
  15. }
  16. //Register filters
  17. @Override
  18. protected Filter[] getServletFilters() {
  19. return new Filter[] { new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };
  20. }
  21. }

请注意,如果您需要自定义DispatcherServlet,则可以覆盖createDispatcherServlet()方法。

4.4. AbstractAnnotationConfigDispatcherServletInitializer示例

该类扩展了AbstractDispatcherServletInitializer并隐式地执行了一些操作,否则您可能会自己做。 另一个优点是,您现在可以使用 Spring 提供的便利类,而不必手动配置DispatcherServlet和/或ContextLoaderListener

对于使用基于 Java 的 Spring 配置的应用程序,这是首选方法。 它使您能够启动 servlet 应用程序上下文以及根应用程序上下文。

AppInitializer.java

  1. public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  2. @Override
  3. protected Class<?>[] getRootConfigClasses() {
  4. return new Class[] { RootConfig.class };
  5. }
  6. @Override
  7. protected Class<?>[] getServletConfigClasses() {
  8. return new Class[] { WebMvcConfig.class };
  9. }
  10. @Override
  11. protected String[] getServletMappings() {
  12. return new String[] { "/" };
  13. }
  14. }

这里RootConfigWebMvcConfig类用于在 root 和 servlet 上下文范围内配置 bean。

阅读更多: Spring 5 MVC 示例

5. 支持DispatcherServlet的 Bean

收到网络请求后,DispatcherServlet将执行一组操作以进行请求处理。 为此,它使用了一组支持 bean。 下表列出了这些默认配置的 Bean 及其职责:

Bean 职责范围
HandlerMapping 将传入的 Web 请求映射到处理器以及预处理器和后处理器
HandlerAdapter 调用用于解析参数和依赖项的处理器,例如用于 URL 映射的控制器方法端点的带注解的参数
HandlerExceptionResolver 允许以编程方式处理异常并将异常映射到视图
ViewResolver 解析逻辑视图名称以查看实例
LocaleResolver 解决客户的语言环境以实现国际化
LocaleContextResolver LocaleResolver的更扩展,带有时区信息
ThemeResolver 解决了在您的应用中配置的主题,以增强用户体验
MultipartResolver 处理多部分文件上传作为 HTTP 请求的一部分
FlashMapManager 管理FlashMap实例,这些实例在彼此重定向的请求之间存储临时 Flash 属性

如果要更改任何 bean 的任何特定行为,则需要覆盖它。

6. Spring DispatcherServlet示例

为了演示DispatcherServlet的使用,我编写了一个非常简单的应用程序,该应用程序仅配置了调度程序 servlet 并覆盖了视图解析程序 bean。

6.1. 项目结构

Spring `DispatcherServlet` – 它是如何工作的? - 图1

Spring5 MVC 项目结构

6.2. AppInitializer.java

AppInitializer.java

  1. package com.howtodoinjava.demo.spring.config;
  2. public class AppInitializer extends
  3. AbstractAnnotationConfigDispatcherServletInitializer {
  4. @Override
  5. protected Class<?>[] getRootConfigClasses() {
  6. return new Class[] { };
  7. }
  8. @Override
  9. protected Class<?>[] getServletConfigClasses() {
  10. return new Class[] { WebMvcConfig.class };
  11. }
  12. @Override
  13. protected String[] getServletMappings() {
  14. return new String[] { "/" };
  15. }
  16. }

6.3. WebMvcConfig.java

WebMvcConfig.java

  1. @Configuration
  2. @EnableWebMvc
  3. @ComponentScan(basePackages = { "com.howtodoinjava.demo.spring"})
  4. public class WebMvcConfig implements WebMvcConfigurer {
  5. @Bean
  6. public InternalResourceViewResolver resolver() {
  7. InternalResourceViewResolver resolver = new InternalResourceViewResolver();
  8. resolver.setViewClass(JstlView.class);
  9. resolver.setPrefix("/WEB-INF/views/");
  10. resolver.setSuffix(".jsp");
  11. return resolver;
  12. }
  13. }

6.4. HomeController.java

HomeController.java

  1. @Controller
  2. public class HomeController
  3. {
  4. @GetMapping("/")
  5. public String homeInit(Locale locale, Model model) {
  6. return "home";
  7. }
  8. }

home.jsp

home.jsp

  1. <html>
  2. <head>
  3. <title>Spring 5 Web MVC Example</title>
  4. </head>
  5. <body>
  6. <h1>HowToDoInJava.com</h1>
  7. <h2>Spring 5 Web MVC DispatcherServlet Example</h2>
  8. </body>
  9. </html>

6.5. pom.xml

pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd;
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.howtodoinjava.spring5.mvc</groupId>
  5. <artifactId>spring5-webmvc-demo</artifactId>
  6. <packaging>war</packaging>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <name>spring5-webmvc-demo Maven Webapp</name>
  9. <url>http://maven.apache.org</url>
  10. <properties>
  11. <failOnMissingWebXml>false</failOnMissingWebXml>
  12. <spring.version>5.2.0.RELEASE</spring.version>
  13. <jstl.version>1.2.1</jstl.version>
  14. <tld.version>1.1.2</tld.version>
  15. <servlets.version>3.1.0</servlets.version>
  16. <jsp.version>2.3.1</jsp.version>
  17. </properties>
  18. <dependencies>
  19. <!-- Spring MVC Dependency -->
  20. <dependency>
  21. <groupId>org.springframework</groupId>
  22. <artifactId>spring-webmvc</artifactId>
  23. <version>${spring.version}</version>
  24. </dependency>
  25. <!-- JSTL Dependency -->
  26. <dependency>
  27. <groupId>javax.servlet.jsp.jstl</groupId>
  28. <artifactId>javax.servlet.jsp.jstl-api</artifactId>
  29. <version>${jstl.version}</version>
  30. </dependency>
  31. <dependency>
  32. <groupId>taglibs</groupId>
  33. <artifactId>standard</artifactId>
  34. <version>${tld.version}</version>
  35. </dependency>
  36. <!-- Servlet Dependency -->
  37. <dependency>
  38. <groupId>javax.servlet</groupId>
  39. <artifactId>javax.servlet-api</artifactId>
  40. <version>${servlets.version}</version>
  41. <scope>provided</scope>
  42. </dependency>
  43. <!-- JSP Dependency -->
  44. <dependency>
  45. <groupId>javax.servlet.jsp</groupId>
  46. <artifactId>javax.servlet.jsp-api</artifactId>
  47. <version>${jsp.version}</version>
  48. <scope>provided</scope>
  49. </dependency>
  50. </dependencies>
  51. <build>
  52. <sourceDirectory>src/main/java</sourceDirectory>
  53. <resources>
  54. <resource>
  55. <directory>src/main/resources</directory>
  56. </resource>
  57. </resources>
  58. <plugins>
  59. <plugin>
  60. <artifactId>maven-compiler-plugin</artifactId>
  61. <version>3.5.1</version>
  62. <configuration>
  63. <source>1.8</source>
  64. <target>1.8</target>
  65. </configuration>
  66. </plugin>
  67. <plugin>
  68. <groupId>org.apache.tomcat.maven</groupId>
  69. <artifactId>tomcat7-maven-plugin</artifactId>
  70. <version>2.2</version>
  71. <configuration>
  72. <path>/</path>
  73. </configuration>
  74. </plugin>
  75. </plugins>
  76. </build>
  77. </project>

6.6. 运行应用程序

要运行应用程序,请执行 maven 目标:tomcat7:run。 现在在浏览器中打开http://localhost:8080

Spring `DispatcherServlet` – 它是如何工作的? - 图2

Spring DispatcherServlet示例截图

将我的问题放在评论部分。

下载源码

学习愉快!