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);
}
相关推荐
菜鸟一枚在这16 分钟前
深度解析建造者模式:复杂对象构建的优雅之道
java·开发语言·算法
gyeolhada33 分钟前
2025蓝桥杯JAVA编程题练习Day5
java·数据结构·算法·蓝桥杯
菜鸟一枚在这35 分钟前
深入理解设计模式之代理模式
java·设计模式·代理模式
剑走偏锋o.O1 小时前
Spring MVC 框架学习笔记:从入门到精通的实战指南
学习·spring·springmvc
小天努力学java1 小时前
【面试系列】Java开发--AI常见面试题
java·人工智能·面试
river661 小时前
java开发——为什么要使用动态代理?
java
Zayn~1 小时前
JVM系列--虚拟机类加载机制
java
m0_748248021 小时前
Redis使用手册
java
CoderCodingNo1 小时前
【GESP】C++二级真题 luogu-b3924, [GESP202312 二级] 小杨的H字矩阵
java·c++·矩阵
2501_903238652 小时前
Spring MVC中环境配置的实战应用
java·spring·mvc·个人开发