Lesson 58 · Spring 生态核心原理

Spring MVC 请求处理全流程:DispatcherServlet 到 View

中级·#Spring MVC·#请求

第 1 站

面试官:一次 HTTP 请求在 Spring 内部经历了哪些组件?

"从 Tomcat 把请求交给 Spring,到最终返回 JSON 响应,中间经过了哪些类?每个组件的职责是什么?如果某个环节抛异常了怎么处理?" —— 这道题考的是你对 Spring MVC 整体架构的宏观理解。

Spring MVC 的核心设计模式是 前端控制器(Front Controller),所有请求统一由 DispatcherServlet 接收,再分发给各个组件处理。

Spring MVC 请求处理全流程 Client DispatcherServlet 前端控制器 总调度中心 HandlerMapping URL → Handler 映射 HandlerAdapter 调用 Handler Controller 业务逻辑 HttpMessageConverter / ViewResolver 响应返回
图 1 Spring MVC 请求处理核心组件与调用链

DispatcherServlet 继承自 HttpServlet,是整个 Spring MVC 的入口。它的核心方法是 doDispatch(),负责协调所有组件:

DispatcherServlet.java · doDispatch 核心流程
protected void doDispatch(HttpServletRequest request,
                          HttpServletResponse response) throws Exception {

    HandlerExecutionChain mappedHandler = null;
    ModelAndView mv = null;
    Exception dispatchException = null;

    try {
        // ① 通过 HandlerMapping 找到处理器
        mappedHandler = getHandler(request);

        // ② 通过 HandlerAdapter 调用处理器
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

        // ③ 执行拦截器 preHandle
        if (!mappedHandler.applyPreHandle(request, response)) { return; }

        // ④ 真正调用 Controller 方法
        mv = ha.handle(request, response, mappedHandler.getHandler());

        // ⑤ 执行拦截器 postHandle
        mappedHandler.applyPostHandle(request, response, mv);
    } catch (Exception ex) {
        dispatchException = ex;
    }

    // ⑥ 处理结果(渲染视图 / 写 JSON / 处理异常)
    processDispatchResult(request, response, mappedHandler, mv, dispatchException);
}
第 2 站

HandlerMapping:URL 到处理器的映射

HandlerMapping 的职责是根据请求 URL 找到对应的处理器(Handler),并组装成 HandlerExecutionChain(包含处理器 + 拦截器链)。

实现类映射方式使用场景
RequestMappingHandlerMapping@RequestMapping 注解最常用,注解驱动
BeanNameUrlHandlerMappingBean 名称以 "/" 开头XML 配置时代遗留
SimpleUrlHandlerMapping显式配置 URL 映射简单静态映射
RequestMappingHandlerMapping · 映射查找过程
// Spring 启动时扫描所有 @Controller / @RestController
// 解析 @RequestMapping,注册到内部映射表:

// 映射表结构(简化)
Map<RequestMappingInfo, HandlerMethod>

// RequestMappingInfo 包含:
//   - URL patterns:    ["/api/users/{id}"]
//   - HTTP methods:    [GET]
//   - headers:         ["Accept=application/json"]
//   - params:          ["type=admin"]
//   - consumes:        ["application/json"]
//   - produces:        ["application/json"]

// HandlerMethod 包含:
//   - bean:            UserController 实例
//   - method:          getUserById() 方法对象

查找过程的返回值是 HandlerExecutionChain,它不仅包含 Handler 本身,还包含匹配到的拦截器:

HandlerExecutionChain.java
public class HandlerExecutionChain {
    private final Object handler;             // 处理器(HandlerMethod)
    private HandlerInterceptor[] interceptors; // 匹配的拦截器数组
}
关键点
HandlerMapping 返回的不只是一个 Handler,而是一个"执行链"——Handler + 拦截器列表。拦截器的 preHandle / postHandle / afterCompletion 会围绕 Handler 的执行形成一个"洋葱模型"。
第 3 站

HandlerAdapter:统一调用不同 Handler

"为什么不直接调用 Controller 方法,中间还要加一层 HandlerAdapter?" —— 适配器模式的经典应用:Handler 可以是任意类型(注解方法、简单 Controller、HttpRequestHandler),HandlerAdapter 将它们统一适配。
HandlerAdapter适配的 Handler 类型说明
RequestMappingHandlerAdapterHandlerMethod处理 @RequestMapping 注解方法(最常用)
HttpRequestHandlerAdapterHttpRequestHandler处理静态资源等低级请求
SimpleControllerHandlerAdapterController 接口老式 Controller 接口实现

RequestMappingHandlerAdapter 是日常使用最多的适配器,它的 handle() 方法内部做了大量工作:

RequestMappingHandlerAdapter · handle 内部流程
protected ModelAndView handleInternal(...) {
    // ① 解析方法参数
    //    @RequestParam → 从 query string / form 取值
    //    @PathVariable → 从 URL 模板变量取值
    //    @RequestBody  → 用 HttpMessageConverter 反序列化
    //    @RequestHeader → 从请求头取值

    // ② 反射调用 Controller 方法
    Object returnValue = method.invoke(bean, args);

    // ③ 处理返回值
    //    @ResponseBody → 用 HttpMessageConverter 序列化为 JSON
    //    String       → 当作视图名交给 ViewResolver
    //    ModelAndView → 包含模型数据和视图名
}

参数解析器和返回值处理器各自维护一个列表,Spring 按顺序匹配第一个支持当前参数/返回类型的处理器:

参数解析器链 · HandlerMethodArgumentResolver
// 常见的参数解析器(按优先级排列)
1. RequestParamMethodArgumentResolver    // @RequestParam
2. PathVariableMethodArgumentResolver    // @PathVariable
3. RequestResponseBodyMethodProcessor    // @RequestBody(兼做返回值)
4. RequestHeaderMethodArgumentResolver   // @RequestHeader
5. ServletRequestMethodArgumentResolver  // HttpServletRequest
6. ModelAttributeMethodProcessor         // @ModelAttribute
第 4 站

Controller 处理与 REST 响应(@ResponseBody)

在现代 REST API 开发中,Controller 方法通常标注 @ResponseBody(或类级别 @RestController),返回值直接写入 HTTP 响应体,不经过视图解析。

UserController.java · REST 风格 Controller
@RestController            // = @Controller + @ResponseBody
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.save(user);
    }
}

@ResponseBody 的序列化流程HttpMessageConverter 完成:

@ResponseBody 返回值 → HTTP 响应体 Controller return User对象 内容协商 Accept: application/json 选择 Converter MappingJackson2 HttpMessageConverter Object → JSON 字符串 HTTP Response {"id":1,"name":".."} 常见 HttpMessageConverter MappingJackson2 → JSON StringHttpMessage → 纯文本 Jaxb2RootElement → XML ByteArray → 二进制流
图 2 @ResponseBody 通过 HttpMessageConverter 序列化返回值
REST API 关键点
在 @RestController 中,返回值不走 ViewResolver,而是通过 HttpMessageConverter 直接序列化写入响应体。Spring Boot 默认使用 Jackson(MappingJackson2HttpMessageConverter)处理 JSON。
第 5 站

ViewResolver:传统视图解析(非 REST 场景)

如果 Controller 返回一个视图名(String 类型,没有 @ResponseBody),Spring 会通过 ViewResolver 将其解析为具体的 View 对象:

传统视图解析流程
@Controller  // 注意:不是 @RestController
public class PageController {

    @GetMapping("/dashboard")
    public String dashboard(Model model) {
        model.addAttribute("user", currentUser);
        return "dashboard";  // 返回视图名
    }
}

// ViewResolver 解析过程:
// "dashboard" → InternalResourceViewResolver
//             → prefix + "dashboard" + suffix
//             → "/WEB-INF/views/dashboard.html"
//             → 渲染 HTML 写入响应体
ViewResolver视图技术说明
InternalResourceViewResolverJSP前缀 + 视图名 + 后缀
ThymeleafViewResolverThymeleafSpring Boot 推荐模板
FreeMarkerViewResolverFreeMarker老牌模板引擎
ContentNegotiatingViewResolver多格式根据 Accept 头选择视图
application.yml · Thymeleaf 配置
spring:
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
    cache: false  # 开发时关闭缓存
REST API 场景下(@ResponseBody / @RestController),ViewResolver 完全不参与。返回值由 HttpMessageConverter 直接写入响应体。现代微服务架构中,ViewResolver 的使用已经越来越少。
第 6 站

异常处理与拦截器

Spring MVC 提供了多层异常处理机制:

异常处理优先级 · 从局部到全局
// 优先级 1:Controller 内的 @ExceptionHandler
@RestController
public class UserController {
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) {
        return ResponseEntity.status(404).body(ex.getMessage());
    }
}

// 优先级 2:@ControllerAdvice 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
        return ResponseEntity.status(500).body(new ErrorResponse(ex));
    }
}

// 优先级 3:HandlerExceptionResolver(框架级别)
// - DefaultHandlerExceptionResolver → 处理 Spring 内部异常
// - ResponseStatusExceptionResolver → 处理 @ResponseStatus

拦截器(HandlerInterceptor)在请求处理的前后执行,形成"洋葱模型":

LoggingInterceptor.java · 拦截器实现
public class LoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest req,
                               HttpServletResponse res,
                               Object handler) {
        // Controller 方法执行前调用
        // 返回 false → 终止请求,不再往下执行
        // 返回 true  → 继续执行下一个拦截器或 Handler
        log.info("Request: {} {}", req.getMethod(), req.getRequestURI());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest req,
                             HttpServletResponse res,
                             Object handler, ModelAndView mv) {
        // Controller 方法执行后、视图渲染前调用
        // 注意:@ResponseBody 场景下 mv 为 null
    }

    @Override
    public void afterCompletion(HttpServletRequest req,
                                  HttpServletResponse res,
                                  Object handler, Exception ex) {
        // 请求完成后调用(包括异常情况)
        // 适合做资源清理、日志记录
    }
}
拦截器洋葱模型 Interceptor A — preHandle Interceptor B — preHandle Controller Handler Interceptor B — postHandle Interceptor A — postHandle preHandle 由外到内,postHandle 由内到外;afterCompletion 在所有情况下都会执行
图 3 拦截器的洋葱模型:preHandle 由外到内,postHandle 由内到外
面试回答模板
  • 总入口:DispatcherServlet.doDispatch() 是所有请求的调度中心
  • 查找处理器:HandlerMapping 根据 URL 匹配 HandlerMethod,返回 HandlerExecutionChain(含拦截器)
  • 调用处理器:HandlerAdapter 适配不同类型的 Handler,解析参数、反射调用、处理返回值
  • REST 响应:@ResponseBody 通过 HttpMessageConverter 将返回值序列化写入响应体,不走 ViewResolver
  • 异常处理:@ExceptionHandler(局部)→ @ControllerAdvice(全局)→ HandlerExceptionResolver(框架)
  • 拦截器:HandlerInterceptor 的 preHandle / postHandle / afterCompletion 形成洋葱模型