SpringMVC执行流程详解

4 阅读7分钟

在Java Web开发领域,SpringMVC作为主流的MVC框架,其核心价值在于实现请求处理与视图渲染的解耦,让开发更具规范性和可维护性。想要熟练运用SpringMVC,首先要理清它的请求执行全流程——从用户发起请求到最终获得响应,每一步都有明确的组件分工,而前端控制器则是整个流程的“中枢神经”。本文将一步步拆解SpringMVC的标准执行流程,结合实战代码示例,让每一个环节的作用都清晰可见。

一、核心组件先了解

在拆解流程前,先明确参与流程的核心组件及其核心职责,这是理解整个流程的基础,无需额外拓展,聚焦核心功能即可:

  • DispatcherServlet:前端控制器,SpringMVC的入口,统一接收所有请求,协调其他所有组件完成请求处理和响应。
  • HandlerMapping:处理器映射器,根据请求的URL和配置,找到对应的处理器(Controller方法),并返回包含处理器和拦截器的执行链。
  • HandlerAdapter:处理器适配器,适配不同类型的处理器,负责解析请求参数、调用具体的处理器方法。
  • Controller:处理器,核心业务逻辑的载体,接收请求、处理业务,最终返回处理结果和视图信息。
  • ViewResolver:视图解析器,将Controller返回的逻辑视图名,解析为实际的视图对象(如JSP、HTML)。
  • View:视图,负责将处理结果的数据渲染为最终的页面,响应给用户。

二、SpringMVC执行流程全拆解(10步走)

下面结合实战代码,一步步拆解SpringMVC从请求发起至响应结束的完整流程,每一步都对应实际开发中的具体场景,让流程更易理解。

步骤1:用户发送HTTP请求至DispatcherServlet

用户通过浏览器、Postman等客户端,发送HTTP请求(如GET请求 /student/query?id=1),该请求会首先被Web容器(如Tomcat)拦截,然后转发给SpringMVC的前端控制器DispatcherServlet。

DispatcherServlet需要在web.xml中配置,确保请求能被正确拦截,配置代码如下:


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"&gt;

    <!-- 配置SpringMVC前端控制器DispatcherServlet -->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
        <!-- 配置SpringMVC配置文件路径 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param&gt;
        <!-- 启动时加载DispatcherServlet -->
        <load-on-startup>1</load-on-startup>
    </servlet&gt;

    <!-- 配置请求映射,所有请求都交给DispatcherServlet处理 -->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>
    

步骤2:DispatcherServlet调用HandlerMapping查找处理器

DispatcherServlet本身不直接处理请求,而是接收请求后,委托HandlerMapping根据请求的URL,查找对应的处理器(即Controller中的具体方法)。

实际开发中,我们常用注解式开发,通过@RequestMapping注解指定请求路径与处理器方法的映射,此时使用的HandlerMapping实现类是RequestMappingHandlerMapping(SpringMVC默认加载)。我们只需在SpringMVC配置文件中开启注解驱动即可,配置如下:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd"&gt;

    <!-- 扫描Controller所在的包让Spring管理 -->
    <context:component-scan base-package="com.example.springmvc.controller"/&gt;

    <!-- 开启SpringMVC注解驱动自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter -->
    &lt;mvc:annotation-driven/&gt;

    <!-- 配置视图解析器ViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
        <!-- 配置视图前缀指定视图文件所在目录 -->
        <property name="prefix" value="/WEB-INF/views/"/&gt;
        <!-- 配置视图后缀指定视图文件格式 -->
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>
    

步骤3:HandlerMapping返回处理器执行链

HandlerMapping根据请求URL匹配到对应的处理器方法后,不会只返回该方法,而是返回一个处理器执行链(HandlerExecutionChain),该执行链包含匹配的处理器(Controller方法)和对应的拦截器(如果有),然后将执行链返回给DispatcherServlet。

这里我们编写一个简单的拦截器示例,演示拦截器如何加入执行链,拦截器代码如下:


package com.example.springmvc.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// 自定义拦截器,实现HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor {

    // 请求处理前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器:请求处理前执行,验证请求合法性");
        // 返回true表示放行,false表示拦截
        return true;
    }
}
    

在SpringMVC配置文件中配置拦截器,使其生效:

<!-- 配置拦截器 -->
<mvc:interceptors>
    <mvc:interceptor><!-- 配置拦截的请求路径,/**表示拦截所有请求 -->
        &lt;mvc:mapping path="/**"/&gt;
        <!-- 配置不拦截的请求路径(可选) -->
        <mvc:exclude-mapping path="/static/**"/&gt;
        <!-- 关联自定义拦截器 -->
        <bean class="com.example.springmvc.interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
    

步骤4:DispatcherServlet调用HandlerAdapter适配处理器

DispatcherServlet接收处理器执行链后,发现无法直接调用处理器方法(因为处理器的形式多样,如注解式、XML配置式),此时需要通过HandlerAdapter进行适配。

结合前面的注解驱动配置,SpringMVC会自动加载RequestMappingHandlerAdapter,该适配器专门适配带有@RequestMapping注解的处理器方法,负责解析请求参数、将参数绑定到处理器方法的形参上。

步骤5:HandlerAdapter调用具体处理器(Controller)

HandlerAdapter完成适配后,会调用具体的处理器方法(Controller中的方法),执行核心业务逻辑。这里我们编写一个简单的Controller,接收请求参数、处理业务,并返回ModelAndView对象,代码如下:


package com.example.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

// 标识该类为Controller处理器
@Controller
@RequestMapping("/student")
public class StudentController {

    // 匹配请求路径 /student/query,接收id参数
    @RequestMapping("/query")
    public ModelAndView queryStudent(@RequestParam("id") Integer studentId) {
        // 模拟业务逻辑:根据id查询学生信息(实际开发中会调用Service层)
        String studentName = "张三";
        Integer age = 20;

        // 创建ModelAndView对象,封装视图和数据
        ModelAndView modelAndView = new ModelAndView();
        // 存入数据到Model(键值对形式,前端可通过EL表达式获取)
        modelAndView.addObject("studentId", studentId);
        modelAndView.addObject("studentName", studentName);
        modelAndView.addObject("age", age);
        // 设置逻辑视图名(视图解析器会根据前缀和后缀解析为实际视图)
        modelAndView.setViewName("studentInfo");

        return modelAndView;
    }
}
    

步骤6:Controller执行并返回ModelAndView

Controller方法执行完成后,会返回一个ModelAndView对象,该对象包含两部分核心信息:Model(处理结果的数据,如查询到的学生信息)和View(逻辑视图名,如上面的“studentInfo”,并非实际的视图文件)。

需要注意的是,Model中的数据会被存入request域中,供前端视图渲染时使用;逻辑视图名则用于后续视图解析器的解析。

步骤7:HandlerAdapter将ModelAndView返回给DispatcherServlet

HandlerAdapter调用完Controller方法后,会将返回的ModelAndView对象,重新传递回DispatcherServlet,由DispatcherServlet继续后续的视图解析和渲染流程。

步骤8:DispatcherServlet委托ViewResolver解析视图

DispatcherServlet接收ModelAndView后,会委托ViewResolver(视图解析器),将逻辑视图名解析为实际的视图对象。结合前面的SpringMVC配置,我们使用的ViewResolver实现类是InternalResourceViewResolver,它会根据配置的前缀(/WEB-INF/views/)和后缀(.jsp),将逻辑视图名“studentInfo”解析为实际的视图文件路径:/WEB-INF/views/studentInfo.jsp。

步骤9:ViewResolver返回具体View给DispatcherServlet

ViewResolver完成视图解析后,会生成一个具体的View对象(这里是JSP视图对象),并将该View对象返回给DispatcherServlet。

我们编写对应的JSP视图文件(studentInfo.jsp),用于渲染Model中的数据,代码如下:


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>学生信息</title>
</head>
<body>
    <h3>学生信息查询结果</h3>
    <div>
        <p>学生ID:${studentId}</p>
        <p>学生姓名:${studentName}</p>
        <p>学生年龄:${age}</p>
    </div>
</body>
</html>
    

步骤10:DispatcherServlet渲染视图并响应用户

DispatcherServlet接收View对象后,会调用View对象的render()方法,将Model中的数据填充到视图中(如JSP页面中的EL表达式studentId{studentId}、{studentName},会被Model中的对应数据替换),生成最终的HTML页面。

最后,DispatcherServlet将渲染完成的HTML页面,通过HTTP响应返回给用户,用户在浏览器中就能看到完整的学生信息页面,整个执行流程结束。

三、流程核心总结

整个SpringMVC执行流程中,DispatcherServlet始终处于核心协调地位,串联起HandlerMapping、HandlerAdapter、ViewResolver等所有组件,实现了“请求接收-业务处理-视图渲染-响应返回”的完整闭环。

组件之间的分工明确,互不耦合:HandlerMapping负责“找处理器”,HandlerAdapter负责“调处理器”,ViewResolver负责“解析视图”,Controller负责“处理业务”,这种分工协作让SpringMVC具备了良好的灵活性和可维护性,也是其成为主流Java Web框架的核心原因。