当前位置: 首页 > article >正文

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

// 核心数据结构
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

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

2.3 HandlerAdapter

// 处理@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 视图渲染

// 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 拦截器定义

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 拦截器调用过程

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

http://www.kler.cn/a/506536.html

相关文章:

  • AIGC时代:如何快速搞定Spring Boot+Vue全栈开发
  • C++算法第十六天
  • 机器学习第一道菜(一):线性回归的理论模型
  • ubuntu下安装编译cmake,grpc与protobuf
  • jmeter事务控制器-勾选Generate Parent Sample
  • 自动驾驶3D目标检测综述(八)
  • BertTokenizerFast 和 BertTokenizer 的区别
  • 探索 AI 自动化编程:效率革命与未来教育的转型
  • Java 对象池管理的高性能工具库 Apache Commons Pool 2
  • 2.两数相加--力扣
  • tomcat文件目录讲解
  • 剑指Offer|LCR 031. LRU 缓存
  • Haskell语言的网络编程
  • 基于 Electron 应用的安全测试基础 — 提取和分析 .asar 文件
  • 【k8s面试题2025】1、练气期
  • 鸿蒙-点击Notification通知并打开App的具体页面
  • 动态规划汇总1
  • 服务器数据恢复—Zfs文件系统数据恢复案例
  • mongDB学习笔记
  • 基于Linux系统指令使用详细解析
  • 浅谈云计算18 | OpenStack架构概述
  • 自动化仓储管理与库存控制
  • 《零基础Go语言算法实战》【题目 4-11】在不使用任何内置散列表库的情况下设计一个 HashSet
  • 蓝桥杯刷题第三天——排序
  • 如何有效防止和解决IP劫持问题
  • Linux中常用命令详解