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);
}
相关推荐
xcl092517 分钟前
宠物救助领养系统实战开发指南:从需求分析到部署上线
java·mfc·宠物
考虑考虑25 分钟前
arthas使用
java·运维·后端
xcl092525 分钟前
从零开发流浪宠物领养平台:技术选型与核心模块设计
java·spring boot·宠物
Dovis(誓平步青云)35 分钟前
模拟器横评:电脑上看小说、追短剧用什么模拟器?MuMu、雷电、腾讯手游助手实测
android·java·服务器·前端·javascript·电脑
JienDa1 小时前
我做了一款不依赖 AI 的离线传统术数排盘工具:Electron、Vue3 与 Java 17 的完整实践
java·人工智能·electron
非凡ghost1 小时前
用 Kotlin 和 Jetpack Compose 重写的安卓视频播放器,原生体验有多流畅?
android·java·kotlin·音视频·软件需求
ttwosix1 小时前
JavaEE初阶 多线程 3
java·开发语言
asdfg12589631 小时前
一个例子通俗理解Java中正则表达式用法
java·正则表达式
一嘴一个橘子1 小时前
MyBatis‑Plus Service 层常用自带方法
java
健康平安的活着1 小时前
java中批量查询+stream返回map提高查询效率
java·windows·python