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

 更新时间:2025年01月16日 11:46:16   作者:小·恐·龙  
该文章详细介绍了SpringMVC的请求处理流程,从Filter链处理开始,经过DispatcherServlet、HandlerMapping、HandlerAdapter、拦截器(前置处理、后置处理、完成处理)到视图渲染,感兴趣的朋友跟随小编一起看看吧

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

一、流程文字描述

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

Filter链处理(入口)

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

DispatcherServlet接收请求

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

寻找Handler

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

获取HandlerAdapter

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

拦截器前置处理

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

Handler处理请求

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

拦截器后置处理

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

视图渲染

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

拦截器完成处理

  • 视图渲染完成后,按逆序调用所有拦截器的afterCompletion方法
  • 无论过程中是否有异常,都会执行afterCompletion

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

到此这篇关于Spring MVC核心组件与请求处理流程的文章就介绍到这了,更多相关Spring MVC请求处理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springcloud gateway如何配置动态路由

    springcloud gateway如何配置动态路由

    本文主要介绍了在SpringCloudGateway中配置动态路由的步骤,包括引入依赖、配置路由源、添加配置中心依赖、配置配置中心、定义路由规则和刷新配置等内容,使路由规则在配置中心更新时,无需重启网关服务即可动态应用新的路由规则
    2024-10-10
  • 一文搞懂Java中的反射机制

    一文搞懂Java中的反射机制

    Java的反射机制是在运行状态中,对于任何一个类,都可以知道这个类的所有属性和方法,对于任何一个对象,都可以调用它所有的方法和属性,修改部分类型信息。本文就来详细讲讲Java反射机制的使用
    2022-07-07
  • Java+JFrame实现贪吃蛇小游戏

    Java+JFrame实现贪吃蛇小游戏

    这篇文章主要为大家详细介绍了Java+JFrame实现贪吃蛇小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • springboot内嵌Tomcat安全漏洞修复方式

    springboot内嵌Tomcat安全漏洞修复方式

    针对CVE-2020-1938漏洞,建议升级Tomcat至安全版本以避免受影响,影响版本包括:Apache Tomcat 9.x小于9.0.31、Apache Tomcat 8.x小于8.5.51、Apache Tomcat 7.x小于7.0.100及Apache Tomcat 6.x,
    2024-10-10
  • 通过实例解析spring环绕通知原理及用法

    通过实例解析spring环绕通知原理及用法

    这篇文章主要介绍了通过实例解析spring环绕通知原理及用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • idea中maven本地仓库jar包打包失败和无法引用的问题解决

    idea中maven本地仓库jar包打包失败和无法引用的问题解决

    本文主要介绍了idea中maven本地仓库jar包打包失败和无法引用的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • 解决IDEA中多模块下Mybatis逆向工程不生成相应文件的情况

    解决IDEA中多模块下Mybatis逆向工程不生成相应文件的情况

    这篇文章主要介绍了解决IDEA中多模块下Mybatis逆向工程不生成相应文件的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 学生视角带你了解Java内部类

    学生视角带你了解Java内部类

    说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉。原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法。今天我们就来一探究竟
    2022-03-03
  • 深入Java Final

    深入Java Final

    本篇文章,小编将为大家介绍Java Final,有需要的朋友可以参考一下
    2013-04-04
  • IDEA Ui设计器JFormDesigner 永久激活插件+注册机(亲测一直在用)

    IDEA Ui设计器JFormDesigner 永久激活插件+注册机(亲测一直在用)

    这篇文章主要介绍了IDEA Ui设计器JFormDesigner 永久激活----插件+注册机 自己一直在用的版本和注册机,非常不错,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友可以参考下
    2022-08-08

最新评论