1. 概述

在 Spring Web 应用中,DispatcherServlet 扮演着前端控制器的角色。它是 Spring MVC 构建 Web 应用和 REST 服务的核心组件。在传统的 Spring Web 项目中,这个 Servlet 是在 web.xml 文件中定义的。

本文将带你完成从 web.xml 向 Spring Boot 应用中 DispatcherServlet 的迁移过程,并展示如何将 FilterServletListener 等组件从 web.xml 映射到 Spring Boot 应用中。

2. Maven 依赖

首先,在 pom.xml 中添加 spring-boot-starter-web 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

✅ 这个 starter 已经内置了对 DispatcherServlet 的支持,省去了手动配置的麻烦。

3. DispatcherServlet

DispatcherServlet 是所有 HTTP 请求的入口,它会将请求分发给对应的 Controller。

在 Servlet 3.x 之前,DispatcherServlet 必须在 web.xml 中手动注册。例如:

<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>

但自从 Servlet 3.x 引入后,可以通过 ServletContainerInitializer 实现编程式注册。

在 Spring Boot 中,得益于自动配置机制,DispatcherServlet 会自动注册并配置,我们无需手动干预。

默认情况下,spring-boot-starter-web 会将 DispatcherServlet 绑定到根路径 /。如果需要自定义路径,可以在 application.properties 中配置:

server.servlet.context-path=/demo
spring.mvc.servlet.path=/baeldung

此时,DispatcherServlet 将监听 http://localhost:8080/demo/baeldung/ 路径。

⚠️ 注意:spring.mvc.servlet.path 是 Spring Boot 2.x 引入的配置项,低版本不支持。

4. 应用配置迁移

在传统 Spring MVC 中,web.xml 用于定义部署描述符,包括 URL 映射、过滤器、监听器等。

而在 Spring Boot 中,这些配置都可以通过 Java 配置类来实现。

4.1. 注册 Filter

我们可以通过实现 Filter 接口创建一个自定义过滤器:

@Component
public class CustomFilter implements Filter {

    Logger logger = LoggerFactory.getLogger(CustomFilter.class);

    @Override
    public void init(FilterConfig filterConfig) {
        // 初始化逻辑
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
        logger.info("CustomFilter is invoked");
        chain.doFilter(request, response);
    }
}

在传统方式中,我们会在 web.xml 中这样注册:

<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 中,只需加上 @Component 注解即可自动注册。

✅ 简单粗暴,告别 XML 配置!

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);
    }
}

传统 web.xml 配置如下:

<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 中,可以通过 ServletRegistrationBean 来注册:

@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");
    }
}

传统 web.xml 配置如下:

<listener>
    <listener-class>CustomListener</listener-class>
</listener>

在 Spring Boot 中,可以使用 ServletListenerRegistrationBean 来注册:

@Bean
public ServletListenerRegistrationBean<ServletContextListener> customListenerBean() {
    ServletListenerRegistrationBean<ServletContextListener> bean = new ServletListenerRegistrationBean<>();
    bean.setListener(new CustomListener());
    return bean;
}

✅ 启动日志输出如下:

2020-09-28 08:50:30.872 INFO 19612 --- [main] c.baeldung.demo.listener.CustomListener: CustomListener is initialized

5. 总结

本文带你完成了从传统 web.xml 到 Spring Boot 的迁移过程,包括 DispatcherServletFilterServletListener 的配置方式。

Spring Boot 的自动配置和 Java 配置机制大大简化了 Web 应用的搭建过程,让你告别繁琐的 XML 配置。✅

虽然 Spring Boot 提供了强大的默认配置,但掌握这些底层机制有助于你更深入地理解 Spring MVC 的工作原理。


原始标题:DispatcherServlet and web.xml in Spring Boot | Baeldung