Spring MVC核心组件与请求处理流程

Spring MVC请求处理完整流程详解

一、流程文字描述

当一个HTTP请求到达服务器后,会经历以下流程:

  1. Filter链处理(入口)

    • 请求首先经过Filter链
    • 每个Filter按照定义的顺序执行doFilter方法的前置处理
    • Filter通过调用chain.doFilter()将请求传递给下一个Filter
  2. DispatcherServlet接收请求

    • 所有Filter处理完后,请求到达DispatcherServlet
    • DispatcherServlet作为前端控制器,统一处理所有请求
  3. 寻找Handler

    • DispatcherServlet调用getHandler方法
    • 遍历所有HandlerMapping,找到与当前URL匹配的Handler
    • 找到Handler后,把Handler和对应的拦截器封装成HandlerExecutionChain对象
  4. 获取HandlerAdapter

    • 根据Handler的类型,遍历所有HandlerAdapter
    • 找到支持该Handler类型的HandlerAdapter
    • HandlerAdapter用于调用Handler并处理参数、返回值等
  5. 拦截器前置处理

    • 按顺序调用HandlerExecutionChain中所有拦截器的preHandle方法
    • 如果任一拦截器的preHandle返回false,则中断请求处理
    • 中断时会触发已执行的拦截器的afterCompletion方法
  6. Handler处理请求

    • 通过HandlerAdapter调用Handler(Controller方法)
    • HandlerAdapter负责参数解析、类型转换
    • Handler执行业务逻辑,返回处理结果
  7. 拦截器后置处理

    • Handler执行完成后,按逆序调用所有拦截器的postHandle方法
    • 此时视图尚未渲染
  8. 视图渲染

    • 根据Handler返回的结果进行视图渲染
    • 如果是@RestController,将返回值转换为JSON/XML等格式
    • 如果是传统@Controller,解析视图名称并渲染视图
  9. 拦截器完成处理

    • 视图渲染完成后,按逆序调用所有拦截器的afterCompletion方法
    • 无论过程中是否有异常,都会执行afterCompletion
  10. Filter链处理(出口)

    • 响应会按照与处理请求相反的顺序经过Filter链
    • 每个Filter执行doFilter方法的后置处理
    • 最终响应返回给客户端

二、关键组件详解

2.1 HandlerMapping

java 复制代码
// 核心数据结构
public class RequestMappingHandlerMapping {
    // 保存URL与处理器方法的映射关系
    private final Map<RequestMappingInfo, HandlerMethod> mappingLookup;
}

// 映射示例
mappingLookup = {
    RequestMappingInfo{
        patterns=/users/{id},    // URL模式
        methods=GET,             // HTTP方法
        params=[],              // 请求参数
        headers=[]              // 请求头
    } -> HandlerMethod{UserController.getUser()}
}

2.2 HandlerExecutionChain

java 复制代码
public class HandlerExecutionChain {
    // Handler本身(如Controller的方法)
    private final Object handler;
    
    // 与Handler关联的拦截器列表
    private List<HandlerInterceptor> interceptors;
}

2.3 HandlerAdapter

java 复制代码
// 处理@RequestMapping注解的方法
public class RequestMappingHandlerAdapter implements HandlerAdapter {
    public ModelAndView handle(request, response, handler) {
        // 1. 解析请求参数
        Object[] args = resolveParameters(request, handler);
        
        // 2. 调用Controller方法
        Object returnValue = invokeMethod(handler, args);
        
        // 3. 处理返回值
        return processReturnValue(returnValue);
    }
}

2.4 视图渲染

java 复制代码
// 1. @RestController(JSON渲染)
@GetMapping("/api/user")
public User getUser() {
    return user;  // 自动转换为JSON
}

// 2. @Controller(HTML渲染)
@GetMapping("/user")
public String user(Model model) {
    model.addAttribute("user", user);
    return "userView";  // 解析为具体视图
}

三、拦截器执行流程

3.1 拦截器定义

java 复制代码
public class LogInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(request, response, handler) {
        System.out.println("LogInterceptor - preHandle");
        return true;
    }
    
    @Override
    public void postHandle(request, response, handler, mv) {
        System.out.println("LogInterceptor - postHandle");
    }
    
    @Override
    public void afterCompletion(request, response, handler, ex) {
        System.out.println("LogInterceptor - afterCompletion");
    }
}

3.2 执行顺序示例

复制代码
Filter1 - 请求处理
    Filter2 - 请求处理
        LogInterceptor - preHandle
            SecurityInterceptor - preHandle
                Controller方法执行
            SecurityInterceptor - postHandle
        LogInterceptor - postHandle
        视图渲染
            SecurityInterceptor - afterCompletion
        LogInterceptor - afterCompletion
    Filter2 - 响应处理
Filter1 - 响应处理

3.3 拦截器调用过程

java 复制代码
// 1. preHandle调用(正序)
for (HandlerInterceptor interceptor : interceptors) {
    if (!interceptor.preHandle(request, response, handler)) {
        triggerAfterCompletion(request, response, handler, null);
        return false;
    }
}

// 2. postHandle调用(逆序)
for (int i = interceptors.length - 1; i >= 0; i--) {
    interceptors[i].postHandle(requestresponse, handler, mv);
}

// 3. afterCompletion调用(逆序)
for (int i = interceptors.length - 1; i >= 0; i--) {
    interceptors[i].afterCompletion(request, response, handler, ex);
}
相关推荐
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ15 分钟前
通过java后端代码来实现给word内容补充格式文本内容控件,以及 设置控件的标记和标题
java·c#·word
無限進步D1 小时前
Java 面向对象高级 接口
java·开发语言
逸Y 仙X2 小时前
文章二十七:ElasticSearch ES查询模板(Search Template)高效复用实战
java·大数据·数据库·elasticsearch·搜索引擎·全文检索
二哈赛车手2 小时前
新人笔记---Spring AI的Advisor以及其底层机制讲解(涉及源码),包含一些遇见的Spring AI的Advisor缺陷问题的解决方案
java·人工智能·spring boot·笔记·spring
薪火铺子2 小时前
Redis 缓存三大问题与解决方案
redis·spring·缓存
AC赳赳老秦2 小时前
接口测试自动化:用 OpenClaw 对接 Postman,实现批量回归测试、测试报告自动生成与推送
java·人工智能·python·算法·elasticsearch·deepseek·openclaw
两年半的个人练习生^_^2 小时前
Java日志框架和使用、日志记录规范
java·开发语言·开发规范
pq2173 小时前
最简单的理解synchronized锁升级
java
杨凯凡3 小时前
【032】排查入门:jstack、heap dump、Arthas 初识
java·开发语言·后端