SpringBoot Web 模块核心组件:从 DispatcherServlet 讲起

做 SpringBoot Web 开发这么久,很多同学只知道写 Controller、Service,却不清楚一个 HTTP 请求从发送到响应,背后到底经过了哪些组件。其实 SpringBoot Web 模块的核心,全围绕一个"调度中心"展开------那就是 DispatcherServlet。

今天就从 DispatcherServlet 入手,把 SpringBoot Web 模块的核心组件讲透,包括它们的作用、执行流程,还有实际开发中需要注意的细节。

先给大家一个核心结论:SpringBoot Web 模块的所有组件,都是为了配合 DispatcherServlet 完成"请求接收→处理→响应"的全流程,DispatcherServlet 就是整个 Web 模块的"总指挥"。


一、先搞懂:DispatcherServlet 到底是什么?

很多同学会把 DispatcherServlet 和普通的 Servlet 搞混,其实它本质上是 Servlet 的子类,是 SpringMVC 提供的核心调度器,也是 SpringBoot Web 模块的入口。

SpringBoot 是"约定大于配置",引入 web 依赖后,会自动配置 DispatcherServlet,我们可以通过一段简单代码,验证它的自动配置:

go 复制代码
1importorg.springframework.boot.SpringApplication;
2importorg.springframework.boot.autoconfigure.SpringBootApplication;
3importorg.springframework.web.servlet.DispatcherServlet;
4importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;
5
6@SpringBootApplication
7publicclassWebCoreApplicationimplementsWebMvcConfigurer{
8
9publicstaticvoidmain(String[] args){
10SpringApplication.run(WebCoreApplication.class, args);
11}
12
13// 验证 DispatcherServlet 自动配置(可选,仅用于测试)
14// 此处代码可直接复制,启动项目后,控制台会打印 DispatcherServlet 相关信息
15@Bean
16publicDispatcherServletdispatcherServlet(){
17DispatcherServlet dispatcherServlet =newDispatcherServlet();
18// 打印调度器信息,验证是否被 Spring 管理
19System.out.println("DispatcherServlet 自动配置成功:"+ dispatcherServlet);
20return dispatcherServlet;
21}
22}

简单说:DispatcherServlet 的核心作用,就是"接收所有 HTTP 请求,然后分发给对应的组件处理,最后把处理结果返回给前端"。它不做具体的业务逻辑,只负责"调度",就像一个项目经理,接收需求(请求),分配给对应开发(组件),最后交付成果(响应)。

⚠️ 有时候我们写的 Controller 接口访问不到,排除路径错误后,大概率是 DispatcherServlet 没被正确自动配置(比如依赖引入不全、启动类没加 @SpringBootApplication 注解)。

二、SpringBoot Web 核心组件

光有 DispatcherServlet 不够,还需要一系列组件配合,才能完成请求处理。这些组件都是 SpringBoot 自动配置的,我们平时不用手动创建,但必须懂它们的作用,否则遇到问题无从下手。下面每个组件都配图文拆解+实操代码,确保能看懂、能复用。

1. 核心组件:HandlerMapping(处理器映射器)

作用:根据请求的 URL,找到对应的 Controller 方法(Handler)。

SpringBoot 中默认使用的是 RequestMappingHandlerMapping,它支持 @RequestMapping、@GetMapping、@PostMapping 等注解,我们可以通过代码自定义 HandlerMapping:

go 复制代码
1importorg.springframework.context.annotation.Bean;
2importorg.springframework.context.annotation.Configuration;
3importorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
4
5@Configuration
6publicclassWebConfig{
7
8// 自定义 HandlerMapping(默认已自动配置,此处仅做演示)
9@Bean
10publicRequestMappingHandlerMappingrequestMappingHandlerMapping(){
11RequestMappingHandlerMapping handlerMapping =newRequestMappingHandlerMapping();
12// 可设置映射规则,比如前缀、拦截规则等
13        handlerMapping.setPrefix("/api");// 所有接口添加 /api 前缀
14return handlerMapping;
15}
16}

补充:如果我们自定义了拦截器,HandlerMapping 还会把拦截器和对应的 Handler 绑定,确保请求先经过拦截器,再进入 Controller。

2. 核心组件:HandlerAdapter(处理器适配器)

作用:调用 Handler(Controller 方法),并处理方法的参数、返回值。

可能有同学会问:DispatcherServlet 找到 Handler 后,为什么不直接调用?因为不同的 Handler 可能有不同的参数类型、返回值类型,HandlerAdapter 就是用来"适配"这些差异,统一调用方式。

SpringBoot 中默认使用的是 RequestMappingHandlerAdapter,我们可以通过代码验证它的作用(比如自定义参数解析):

go 复制代码
1importorg.springframework.context.annotation.Bean;
2importorg.springframework.context.annotation.Configuration;
3importorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
4
5@Configuration
6publicclassWebConfig{
7
8// 验证 HandlerAdapter 的作用(自定义参数解析,简化版)
9@Bean
10publicRequestMappingHandlerAdapterrequestMappingHandlerAdapter(){
11RequestMappingHandlerAdapter adapter =newRequestMappingHandlerAdapter();
12// 此处可添加自定义参数解析器,比如解析自定义注解参数
13System.out.println("HandlerAdapter 初始化完成,负责参数解析和方法调用");
14return adapter;
15}
16}

⚠️ 如果 Controller 方法的参数绑定失败(比如 @RequestBody 对应的 JSON 格式错误),就是 HandlerAdapter 解析失败,会返回 400 错误。

3. 核心组件:HandlerExceptionResolver(异常处理器)

作用:处理请求过程中出现的异常(比如 Controller 方法抛出的异常、拦截器抛出的异常),避免直接返回错误页面,统一返回格式。

这就是我们之前讲的"全局异常处理"的底层原理------我们自定义的 @RestControllerAdvice 全局异常处理器,本质上就是实现了 HandlerExceptionResolver 接口:

go 复制代码
1importorg.springframework.web.bind.annotation.ExceptionHandler;
2importorg.springframework.web.bind.annotation.RestControllerAdvice;
3
4// 自定义全局异常处理器(实现 HandlerExceptionResolver 功能,Spring 自动识别)
5@RestControllerAdvice
6publicclassGlobalExceptionHandler{
7
8// 处理所有未捕获的异常
9@ExceptionHandler(Exception.class)
10publicResult<?>handleException(Exception e){
11        e.printStackTrace();
12returnResult.fail(500,"服务器异常:"+ e.getMessage());
13}
14
15// 处理参数绑定异常(HandlerAdapter 解析失败时触发)
16@ExceptionHandler(IllegalArgumentException.class)
17publicResult<?>handleIllegalArgumentException(IllegalArgumentException e){
18returnResult.fail(400,"参数错误:"+ e.getMessage());
19}
20}

4. 核心组件:ViewResolver(视图解析器)

作用:把 Controller 方法返回的视图名称,解析成具体的视图(比如 HTML 页面)。

注意:前后端分离项目中,我们的 Controller 方法一般返回 JSON(用 @ResponseBody 注解),所以 ViewResolver 基本用不到;但如果是传统的 JSP 项目,ViewResolver 就很重要,代码示例如下:

go 复制代码
1importorg.springframework.context.annotation.Bean;
2importorg.springframework.context.annotation.Configuration;
3importorg.springframework.web.servlet.view.InternalResourceViewResolver;
4
5@Configuration
6publicclassWebConfig{
7
8// 传统 JSP 项目,配置 ViewResolver
9@Bean
10publicInternalResourceViewResolverviewResolver(){
11InternalResourceViewResolver viewResolver =newInternalResourceViewResolver();
12// 设置视图前缀和后缀,解析视图名称
13        viewResolver.setPrefix("/WEB-INF/jsp/");
14        viewResolver.setSuffix(".jsp");
15return viewResolver;
16}
17}

SpringBoot 中默认的 ViewResolver 是 InternalResourceViewResolver,适合传统 JSP 项目;前后端分离项目中,我们可以忽略它,专注于 JSON 返回即可。

5. 核心组件:HttpMessageConverter(消息转换器)

作用:实现"请求体→Java 对象"和"Java 对象→响应体"的转换,也就是我们之前讲的 JSON 格式化、日期格式化的底层组件。

我们之前自定义的全局日期格式化、Long 转 String,都是通过配置 HttpMessageConverter(MappingJackson2HttpMessageConverter)实现的:

go 复制代码
1importcom.fasterxml.jackson.databind.ser.std.ToStringSerializer;
2importcom.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
3importcom.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
4importorg.springframework.context.annotation.Bean;
5importorg.springframework.context.annotation.Configuration;
6importorg.springframework.http.converter.HttpMessageConverter;
7importorg.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
8importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;
9
10importjava.time.LocalDateTime;
11importjava.time.format.DateTimeFormatter;
12importjava.util.List;
13
14@Configuration
15publicclassWebConfigimplementsWebMvcConfigurer{
16
17// 全局日期格式
18privatestaticfinalStringDEFAULT_DATE_TIME_FORMAT="yyyy-MM-dd HH:mm:ss";
19
20// 自定义 HttpMessageConverter,实现全局 JSON 格式化
21@Override
22publicvoidconfigureMessageConverters(List<HttpMessageConverter<?>> converters){
23        converters.add(jsonConverter());
24}
25
26@Bean
27publicMappingJackson2HttpMessageConverterjsonConverter(){
28MappingJackson2HttpMessageConverter converter =newMappingJackson2HttpMessageConverter();
29com.fasterxml.jackson.databind.ObjectMapper objectMapper =newcom.fasterxml.jackson.databind.ObjectMapper();
30
31// 1. 全局日期格式化
32JavaTimeModule timeModule =newJavaTimeModule();
33        timeModule.addSerializer(LocalDateTime.class,
34newLocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
35
36// 2. Long 转 String,解决前端 JS 精度丢失
37com.fasterxml.jackson.databind.module.SimpleModule longModule =newcom.fasterxml.jackson.databind.module.SimpleModule();
38        longModule.addSerializer(Long.class,ToStringSerializer.instance);
39        longModule.addSerializer(Long.TYPE,ToStringSerializer.instance);
40
41// 注册模块
42        objectMapper.registerModule(timeModule);
43        objectMapper.registerModule(longModule);
44
45        converter.setObjectMapper(objectMapper);
46return converter;
47}
48}

三、HTTP 请求完整执行链路

理解了核心组件,再看整个请求链路,就非常清晰了,这也是面试常问的知识点,结合图文和步骤,不用死背:

  1. 前端发送 HTTP 请求(比如 GET /user/1),请求先到达 Tomcat 容器;

  2. Tomcat 把请求转发给 SpringBoot 的 DispatcherServlet(所有请求都会经过它);

  3. DispatcherServlet 调用 HandlerMapping,根据请求 URL 找到对应的 Controller 方法(Handler);

  4. DispatcherServlet 调用 HandlerAdapter,由 HandlerAdapter 调用找到的 Controller 方法,处理业务逻辑(调用 Service、Mapper);

  5. Controller 方法返回结果(Java 对象/视图名称),HandlerAdapter 把结果返回给 DispatcherServlet;

  6. 如果返回的是 Java 对象(前后端分离),DispatcherServlet 调用 HttpMessageConverter,把 Java 对象转换成 JSON 字符串;

  7. 如果返回的是视图名称(传统项目),DispatcherServlet 调用 ViewResolver,解析成具体视图;

  8. 如果请求过程中出现异常,HandlerExceptionResolver 会捕获异常,处理后返回统一格式;

  9. DispatcherServlet 把最终的响应结果(JSON/视图)返回给 Tomcat,再由 Tomcat 返回给前端,完成整个流程。

一句话总结:所有请求都绕不开 DispatcherServlet,它串联起所有核心组件,完成请求的调度和处理。

四、实际开发注意事项

  1. DispatcherServlet 自动配置:SpringBoot 引入 spring-boot-starter-web 依赖后,会自动配置 DispatcherServlet,默认映射所有 URL(/*),不用手动配置;

  2. 组件自定义:如果默认的组件不满足需求(比如自定义日期格式化、自定义异常处理),可以通过配置类重写对应的组件(比如自定义 HttpMessageConverter、自定义 HandlerExceptionResolver);

  3. 请求拦截:我们之前讲的 Filter(过滤器)是在 Tomcat 层面拦截请求,早于 DispatcherServlet;Interceptor(拦截器)是在 DispatcherServlet 之后、Controller 之前拦截,两者顺序不要搞混;

  4. 参数解析失败:如果 Controller 方法参数绑定失败,检查 HttpMessageConverter 配置(比如 JSON 格式错误、参数类型不匹配)。

五、最后总结

SpringBoot Web 模块的核心,就是以 DispatcherServlet 为调度中心,配合 HandlerMapping、HandlerAdapter、HttpMessageConverter 等组件,完成 HTTP 请求的接收、处理和响应。

我们日常开发中,写 Controller、自定义全局异常、配置 JSON 格式化,本质上都是在围绕这些核心组件做扩展。懂了这些组件的作用和执行链路,不仅能解决日常开发中的问题,面试时也能从容应对相关问题。

相关推荐
王者鳜錸2 小时前
闲鱼商品自动发布实战:基于Java实现API轮询与批量上架
java·开发语言·python·商品自动发布
asdzx672 小时前
使用 Python 将图片转换为 PDF (含合并)
前端·python·pdf
英俊潇洒美少年2 小时前
Vue 与 React 优缺点全面对比
前端·vue.js·react.js
sjmaysee2 小时前
PostgreSQL异常:An IO error occurred while sending to the backend
java
大白要努力!2 小时前
Android libVLC 3.5.1 实现 RTSP 视频播放完整方案
android·java·音视频
流星雨在线2 小时前
SpringBoot 从开发到打包发布完整教程(对比 Node.js)
spring boot·后端·node.js
liuyao_xianhui2 小时前
优选算法_岛屿数量_floodfill算法)_bfs_C++
java·开发语言·数据结构·c++·算法·链表·宽度优先
321茄子2 小时前
idea 撤销吴提交代码
java·ide·intellij-idea
蜜獾云2 小时前
windows java jar 包后台运行
java