Spring Boot 中的 DispatcherServlet 和 web.xml
1、概览
DispatcherServlet
是 Spring Web 应用的前端控制器(Front Controller)。它用于在 Spring MVC 中创建 Web 应用和 REST 服务。在传统的 Spring Web 应用中,该 Servlet 是在 web.xml
文件中定义的。
本文将会带你了解如何在 Spring Boot 项目中配置 DispatcherServlet
,以及如何配置 web.xml
中的 Filter
、Servlet
和 Listener
。
2、Maven 依赖
首先,在 pom.xml
文件中添加 spring-boot-starter-web Maven 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3、DispatcherServlet
DispatcherServlet
接收所有 HTTP 请求,并将其调度给 Controller 类。
在 Servlet 3.x 规范发布之前,DispatcherServlet
会在 Spring MVC 应用的 web.xml
文件中注册。自 Servlet 3.x 规范发布后,可以使用 ServletContainerInitializer
以编程方式注册 Servlet
。
web.xml
文件中的 DispatcherServlet
配置示例:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Spring Boot 为使用 Spring MVC 开发 Web 应用提供了开箱即用的 spring-boot-starter-web
组件。Spring Boot 的主要功能之一是自动配置。Spring Boot 自动配置会自动注册和配置 DispatcherServlet
。因此,我们无需手动注册它。
默认情况下,spring-boot-starter-web
Starter 会将 DispatcherServlet
的 URL Pattern 配置为 "/"
。因此,无需在 web.xml
文件中为上述 DispatcherServlet
示例进行任何额外配置。不过,你可以在 application.properties
文件中使用 server.servlet.*
自定义 URL Pattern:
server.servlet.context-path=/demo
spring.mvc.servlet.path=/baeldung
如上,DispatcherServlet
的 URL Pattern 配置为 /baeldung
,Root ContextPath 是 /demo
。因此,DispatcherServlet
会处理 http://localhost:8080/demo/baeldung/
下的请求。
4、应用配置
Spring MVC Web 应用除了将 web.xml
文件用作部署描述符文件外,它还定义了 Filter
、Servlet
、Listener
以及他们对应的 URL 映射。
在 Spring Boot 中则有所更改。当我们想从传统的 Spring MVC 迁移到现代的 Spring Boot 应用时,如何将 web.xml
中配置的组件移植到新的 Spring Boot 应用中呢?在 Spring Boot 应用中,可以通过多种方式添加这些 Servlet 组件。
4.1、注册 Filter
通过实现 Filter
接口来创建一个 Filter
:
@Component
public class CustomFilter implements Filter {
Logger logger = LoggerFactory.getLogger(CustomFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.info("CustomFilter is invoked");
chain.doFilter(request, response);
}
// 其他方法
}
如果没有 Spring Boot,则需要在 web.xml
文件中配置 CustomFilter
,如下:
<filter>
<filter-name>customFilter</filter-name>
<filter-class>CustomFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>customFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
要让 Spring Boot 加载 Filter
,只需要在 Filter
类上注解 @Component
,使之成为一个 Spring Bean 即可。
4.2、注册 Servlet
通过继承 HttpServlet
类来定义一个 servlet:
public class CustomServlet extends HttpServlet {
Logger logger = LoggerFactory.getLogger(CustomServlet.class);
@Override
protected void doGet(
HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
logger.info("CustomServlet doGet() method is invoked");
super.doGet(req, resp);
}
@Override
protected void doPost(
HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
logger.info("CustomServlet doPost() method is invoked");
super.doPost(req, resp);
}
}
如果没有 Spring Boot,则需要在 web.xml
文件中配置 CustomServlet
,如下:
<servlet>
<servlet-name>customServlet</servlet-name>
<servlet-class>CustomServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>customServlet</servlet-name>
<url-pattern>/servlet</url-pattern>
</servlet-mapping>
在 Spring Boot 应用中,Servlet
可以通过以下两种方式进行注册:作为 Spring 的 @Bean
或通过扫描带有嵌入式容器 @WebServlet
注解的类来注册。
可以通过 ServletRegistrationBean
类以 Spring @Bean
的方式来注册 Servlet。
使用 ServletRegistrationBean
类把 CustomServlet
定义为一个 Bean:
@Bean
public ServletRegistrationBean customServletBean() {
ServletRegistrationBean bean = new ServletRegistrationBean(new CustomServlet(), "/servlet");
return bean;
}
4.3、注册 Listener
通过继承 ServletContextListener
类来定义一个监听器:
public class CustomListener implements ServletContextListener {
Logger logger = LoggerFactory.getLogger(CustomListener.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
logger.info("CustomListener is initialized");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
logger.info("CustomListener is destroyed");
}
}
如果没有 Spring Boot,则需要在 web.xml
文件中配置 CustomListener
:
<listener>
<listener-class>CustomListener</listener-class>
</listener>
可以使用 @Bean
或 @WebListener
注解在 Spring Boot 应用中定义监听器。
可以通过 ServletListenerRegistrationBean
类以 Spring @Bean
的方式来注册 Listener
。
使用 ServletListenerRegistrationBean
类将 CustomListener
定义为一个 Bean:
@Bean
public ServletListenerRegistrationBean<ServletContextListener> customListenerBean() {
ServletListenerRegistrationBean<ServletContextListener> bean = new ServletListenerRegistrationBean();
bean.setListener(new CustomListener());
return bean;
}
启动应用后,可以查看日志输出,确认 Listener
已成功初始化:
2020-09-28 08:50:30.872 INFO 19612 --- [main] c.baeldung.demo.listener.CustomListener: CustomListener is initialized
5、总结
本文介绍了如何在 Spring Boot 应用中定义 DispatcherServlet
和 web.xml
中的元素(包括 Filter
、Servlet
和 Listener
)。
Ref:https://www.baeldung.com/spring-boot-dispatcherservlet-web-xml