小陈的知识图谱
SpringL3 深入核心重点

Spring MVC 流程

DispatcherServlet、HandlerMapping、HandlerAdapter、拦截器

Spring MVC 请求处理流程

核心流程图

┌──────────────────────────────┐
                     │    客户端(浏览器/App)        │
                     └─────────────┬────────────────┘
                                   │ HTTP 请求
                                   ▼
                     ┌──────────────────────────────┐
                     │      DispatcherServlet        │  (前端控制器)
                     │  doDispatch() 完成请求分发     │
                     └──────┬───────────────┬───────┘
                            │               │
                            ▼               ▼
              ┌─────────────────┐  ┌──────────────────┐
              │  HandlerMapping  │  │  HandlerAdapter  │
              │  查找 Handler    │  │  执行 Handler    │
              │  @RequestMapping │  │  调用 Controller │
              │  URL -> 方法映射  │  │  方法反射调用    │
              └────────┬────────┘  └─────────┬────────┘
                       │                     │
                       └──────────┬──────────┘
                                  ▼
                     ┌──────────────────────────────┐
                     │         Controller            │
                     │    执行业务逻辑,返回结果       │
                     └──────────────┬───────────────┘
                                    │
                          ┌─────────┴─────────┐
                          │                   │
                          ▼                   ▼
              ┌──────────────────┐  ┌──────────────────┐
              │   @ResponseBody  │  │   ModelAndView   │
              │  HttpMessageConv │  │   ViewResolver   │
              │  JSON 直接输出   │  │   视图渲染       │
              └──────────────────┘  └──────────────────┘
                          │                   │
                          └─────────┬─────────┘
                                    ▼
                     ┌──────────────────────────────┐
                     │       HTTP 响应               │
                     └──────────────────────────────┘

doDispatch 源码核心逻辑

// DispatcherServlet.java(核心源码简化)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    try {
        // 1. 检查是否是文件上传请求
        processedRequest = checkMultipart(request);
        multipartRequestParsed = (processedRequest != request);

        // 2. HandlerMapping 查找 Handler(控制器方法)
        mappedHandler = getHandler(processedRequest);
        if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
        }

        // 3. HandlerAdapter 包装 Handler(适配不同类型的处理器)
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

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

        // 5. HandlerAdapter 实际调用目标方法
        ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

        // 6. 执行拦截器 postHandle
        mappedHandler.applyPostHandle(processedRequest, response, mv);

        // 7. 视图渲染
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

    } catch (Exception ex) {
        // 异常处理
        processDispatchResult(..., mappedHandler, ..., ex);
    } finally {
        // 8. 执行拦截器 afterCompletion
        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, ex);
        }
    }
}

---

核心组件详解

1. HandlerMapping —— 请求路由

// 核心接口:将请求映射到 Handler(控制器方法)
public interface HandlerMapping {
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

// 常见实现类
// - RequestMappingHandlerMapping :解析 @RequestMapping(最常用)
// - SimpleUrlHandlerMapping     :显式 URL 模式匹配
// - BeanNameUrlHandlerMapping   :Bean 名称为 URL

RequestMappingHandlerMapping 工作流程:

启动时解析所有 @RequestMapping 注解
        │
        ▼
Map<String, AbstractHandlerMethodMapping.T>

Key: 请求条件(路径、方法、参数等)
Value: HandlerMethod 对象
        │
        ▼
请求到达时匹配 → 路径模板匹配 → 参数匹配 → 找到对应方法

2. HandlerAdapter —— 方法调用器

public interface HandlerAdapter {
    // 是否支持此 Handler
    boolean supports(Object handler);

    // 执行 Handler,返回 ModelAndView
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    // 获取最后修改时间戳
    long getLastModified(HttpServletRequest request, Object handler);
}

// 常见实现
// RequestMappingHandlerAdapter :执行 @RequestMapping 方法(最常用,解析参数/返回值)
// HttpRequestHandlerAdapter    :执行 HttpRequestHandler
// SimpleControllerHandlerAdapter:执行 Controller 接口

RequestMappingHandlerAdapter 的参数解析能力:

@RestController
public class DemoController {

    @GetMapping("/demo/{id}")
    public Result<?> demo(
        // 路径变量
        @PathVariable Long id,

        // 请求参数
        @RequestParam(defaultValue = "10") int size,

        // 请求头
        @RequestHeader("User-Agent") String userAgent,

        // Cookie
        @CookieValue("sessionId") String sessionId,

        // 请求体自动反序列化
        @RequestBody @Valid UserCreateRequest request,

        // 自动绑定到对象属性
        @Valid UserQuery query,

        // 原生 Servlet API 支持
        HttpServletRequest servletRequest,
        HttpServletResponse servletResponse,

        // 时区/地区
        @RequestAttribute TimeZone timeZone,
        Locale locale
    ) {
        return Result.success(query);
    }
}

3. ViewResolver —— 视图解析

public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

常见实现:

  • InternalResourceViewResolver:JSP 视图 prefix + viewName + suffix
  • ThymeleafViewResolver:Thymeleaf 模板引擎
  • FreeMarkerViewResolver:FreeMarker 模板引擎
  • ContentNegotiatingViewResolver:根据请求内容类型选择不同视图

目前主流是前后端分离,使用 @ResponseBody 直接返回 JSON:

@RestController  // = @Controller + @ResponseBody
public class UserController {

    // 直接返回对象,自动序列化为 JSON
    @GetMapping("/users")
    public Result<List<User>> list() {
        return Result.success(userService.findAll());
    }

    // 返回 JSON 状态码
    @PostMapping("/users")
    public ResponseEntity<User> create(@RequestBody @Valid UserCreateRequest request) {
        User created = userService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
}

HttpMessageConverter 机制:

请求到达 → Content-Type: application/json
        │
        ▼
读取请求体 → Jackson 反序列化 → 方法参数对象
        │
        ▼
方法执行完毕 → 返回值 → Jackson 序列化 → JSON 响应体
        │
        ▼
涉及的 HttpMessageConverter:
  • MappingJackson2HttpMessageConverter :JSON
  • StringHttpMessageConverter :普通文本
  • ByteArrayHttpMessageConverter :字节数组
  • FormHttpMessageConverter :表单数据

---

拦截器详解

实现自定义拦截器

@Component
public class AuthInterceptor implements HandlerInterceptor {

    // 在 Handler 执行之前调用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {

        String token = request.getHeader("Authorization");

        // 放行登录/注册接口
        String path = request.getRequestURI();
        if (path.contains("/auth/login") || path.contains("/auth/register")) {
            return true;
        }

        // 验证 Token
        if (token == null || !token.startsWith("Bearer ")) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType("application/json");
            response.getWriter().write("{\"code\":401,\"msg\":\"未登录\"}");
            return false;
        }

        // 解析 Token 设置当前用户
        String userId = JwtUtil.parseToken(token.substring(7));
        request.setAttribute("currentUserId", userId);

        return true;  // 返回 true 继续执行,false 终止
    }

    // 在 Handler 执行之后、视图渲染之前调用(可以修改 ModelAndView)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView modelAndView) throws Exception {
        // 对于 REST API 通常不需要此方法
    }

    // 请求完成后回调(无论是否异常)
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) throws Exception {
        // 清理资源、记录请求日志等
        long duration = System.currentTimeMillis() - (Long) request.getAttribute("startTime");
        log.info("请求完成: {} {} 耗时: {}ms", request.getMethod(), request.getRequestURI(), duration);
    }
}

注册拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;

    @Autowired
    private RateLimitInterceptor rateLimitInterceptor;

    @Autowired
    private RequestLogInterceptor requestLogInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(requestLogInterceptor)
                .addPathPatterns("/**")
                .order(1);

        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/auth/", "/api/public/")
                .order(2);

        registry.addInterceptor(rateLimitInterceptor)
                .addPathPatterns("/api/**")
                .order(3);
    }
}

拦截器 vs 过滤器

请求进入
    │
    ▼
┌──────────────────────┐
│   Filter(Web 容器层) │  ● 基于 Servlet 规范
│   1. CharacterEncoding│  ● 可以处理所有资源(静态/动态)
│   2. CorsFilter       │  ● 无法获取 Spring Bean
│   3. SecurityFilter   │  ● 在 Interceptor 之前执行
│  ...                 │
└──────────┬───────────┘
           ▼
┌──────────────────────┐
│ DispatcherServlet    │  ← Spring MVC 入口
└──────────┬───────────┘
           ▼
┌──────────────────────┐
│  Interceptor(Spring)│  ● Spring 框架层
│   1. preHandle       │  ● 只能处理 Controller 请求
│   2. postHandle      │  ● 可获取 Spring Bean
│   3. afterCompletion │  ● 细粒度路径匹配
└──────────────────────┘
           ▼
     Controller 方法

---

全局异常处理

// 统一异常响应格式
@Data
@AllArgsConstructor
public class ErrorResponse {
    private int code;
    private String message;
    private long timestamp;
}

// 自定义业务异常
public class BusinessException extends RuntimeException {
    private final int code;

    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
    }

    public int getCode() { return code; }
}

// 全局异常处理器
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    // 处理自定义业务异常
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException e) {
        log.warn("业务异常: code={}, msg={}", e.getCode(), e.getMessage());
        return ResponseEntity
            .badRequest()
            .body(new ErrorResponse(e.getCode(), e.getMessage(), System.currentTimeMillis()));
    }

    // 处理参数校验失败
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationException(
            MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
            .map(error -> error.getField() + ": " + error.getDefaultMessage())
            .collect(Collectors.joining(", "));
        return ResponseEntity
            .badRequest()
            .body(new ErrorResponse(400, message, System.currentTimeMillis()));
    }

    // 处理参数类型不匹配
    @ExceptionHandler(TypeMismatchException.class)
    public ResponseEntity<ErrorResponse> handleTypeMismatch(TypeMismatchException e) {
        return ResponseEntity
            .badRequest()
            .body(new ErrorResponse(400, "参数类型错误: " + e.getPropertyName(), System.currentTimeMillis()));
    }

    // 处理资源不存在
    @ExceptionHandler(NoResourceFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(NoResourceFoundException e) {
        return ResponseEntity
            .status(HttpStatus.NOT_FOUND)
            .body(new ErrorResponse(404, "资源不存在", System.currentTimeMillis()));
    }

    // 兜底:处理未预期的异常
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception e) {
        log.error("系统异常", e);
        return ResponseEntity
            .status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body(new ErrorResponse(500, "系统繁忙,请稍后重试", System.currentTimeMillis()));
    }
}

---

完整 REST API 实战案例

// 实体
@Data
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank(message = "用户名不能为空")
    @Column(unique = true, nullable = false, length = 50)
    private String username;

    @Email(message = "邮箱格式不正确")
    @Column(nullable = false, length = 100)
    private String email;

    @Min(value = 1, message = "年龄必须大于0")
    @Max(value = 150, message = "年龄不能超过150")
    private Integer age;

    @Column(nullable = false)
    private Boolean enabled = true;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createdAt;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updatedAt;
}

// 请求 DTO
@Data
public class UserCreateRequest {
    @NotBlank
    @Size(min = 2, max = 50)
    private String username;

    @Email
    @NotBlank
    private String email;

    @Min(1)
    @Max(150)
    private Integer age;
}

// 响应 DTO
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult<T> {
    private List<T> content;
    private int page;
    private int size;
    private long total;
    private int totalPages;
}

// 控制器
@RestController
@RequestMapping("/api/users")
@Validated
@Slf4j
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public Result<PageResult<User>> list(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(required = false) String keyword) {
        PageResult<User> result = userService.findPage(page, size, keyword);
        return Result.success(result);
    }

    @GetMapping("/{id}")
    public Result<User> getById(@PathVariable @Positive Long id) {
        return Result.success(userService.findById(id));
    }

    @PostMapping
    public ResponseEntity<Result<User>> create(
            @RequestBody @Valid UserCreateRequest request) {
        User user = userService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(Result.success(user));
    }

    @PutMapping("/{id}")
    public Result<User> update(
            @PathVariable @Positive Long id,
            @RequestBody @Valid UserCreateRequest request) {
        return Result.success(userService.update(id, request));
    }

    @DeleteMapping("/{id}")
    public Result<Void> delete(@PathVariable @Positive Long id) {
        userService.delete(id);
        return Result.success();
    }

    @PatchMapping("/{id}/status")
    public Result<User> toggleStatus(@PathVariable @Positive Long id) {
        return Result.success(userService.toggleStatus(id));
    }
}

---

异步处理

@RestController
@RequestMapping("/async")
public class AsyncController {

    // 方式一:Callable(在异步线程池执行)
    @GetMapping("/callable")
    public Callable<String> handleCallable() {
        log.info("主线程: {}", Thread.currentThread().getName());
        return () -> {
            Thread.sleep(1000);
            log.info("异步线程: {}", Thread.currentThread().getName());
            return "异步结果";
        };
    }

    // 方式二:DeferredResult(由其他线程设置结果)
    @GetMapping("/deferred")
    public DeferredResult<String> handleDeferred() {
        DeferredResult<String> result = new DeferredResult<>(5000L); // 超时5秒

        // 超时回调
        result.onTimeout(() -> {
            result.setErrorResult("请求超时");
        });

        // 完成回调
        result.onCompletion(() -> {
            log.info("请求完成");
        });

        // 模拟其他线程设置结果
        new Thread(() -> {
            try {
                Thread.sleep(2000);
                result.setResult("DeferredResult 结果");
            } catch (InterruptedException e) {
                result.setErrorResult(e);
            }
        }).start();

        return result;
    }

    // 异步配置
    @Configuration
    public static class AsyncConfig implements WebMvcConfigurer {
        @Override
        public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
            configurer.setDefaultTimeout(30000);
            configurer.setTaskExecutor(new ThreadPoolTaskExecutor());
        }
    }
}

---

面试高频题

Q1: DispatcherServlet 的工作流程?

A: 1. 接收请求 2. HandlerMapping 查找 Handler 3. HandlerAdapter 执行 4. 解析视图(或直接返回 JSON)5. 返回响应。具体步骤参见 doDispatch 源码。

Q2: @ControllerAdvice 的原理?

A: 使用 AOP 的思想,在目标 Controller 执行前后增强。通过 ExceptionHandlerExceptionResolver 匹配异常类型和执行对应的方法。

Q3: 拦截器和过滤器的区别?

A: Filter 是 Servlet 规范,在 DispatcherServlet 之前执行,不能获取 Spring Bean。Interceptor 是 Spring 框架,在 Handler 前后执行,可以获取 Bean,更精细的路径匹配。

Q4: RESTful 接口设计规范?

A: 资源命名用名词复数(/users),用 HTTP 方法表示操作(GET/查、POST/增、PUT/全量更新、PATCH/部分更新、DELETE/删),使用状态码(201 Created、204 No Content、400 Bad Request、404 Not Found、500 Internal Server Error)。

---

核心要点

  • DispatcherServlet 请求处理流程
  • HandlerMapping/HandlerAdapter 作用
  • 拦截器与过滤器区别
  • RESTful 接口设计规范
  • 全局异常处理机制