Featured image of post Java工程师 SpringMVC执行流程

Java工程师 SpringMVC执行流程

🌏Java工程师 SpringMVC执行流程&&编码实现 🎯这篇文章用于记录 对SpringMVC原理实现的实践 包括 1️⃣原理分析 分析在使用Spring框架的时候 MVC是如何为我们工作的 分析MVC的实现原理 2️⃣流程分析 分析整个MVC容器的工作流程 3️⃣过程实现 编码模拟实现MVC

🎄SpringMVC的执行流程

🍭概述

先用一句话概括 SpringMVC就是Servlet的强大的实现的封装✨

在JavaWeb的开发中 其实单单使用Servlet理论上就可以解决所有的问题(获取请求的数据和页面、渲染后返回给客户端) 只不过实现过程是使用原始的API 所以会更费力 工作量更大 SpringMVC也需要做这些事情 但是它让之前的繁琐工作得以简化

SpringMVC做的事情就是把一些通用的底层代码🧱封装起来 同时提供一些好用的注解 把底层代码隐藏起来 只面向更高层的接口进行开发 从而提升开发效率

在SpringMVC中 最核心的一个类就是🎯DispatchServlet 其实它就是一个Servlet的实现类 拥有强大的功能 可以将它称为中央分发控制器 它参与了整个后端响应客户端请求的过程 下图的SpringMVC的执行流程可见DispatchServlet 在SpringMVC的执行流程中所担当的核心角色

从图中我们可以看到 SpringMVC做的事情的⚡流程:

  1. 先获取处理器执行链 这个执行链其实就是客户端的请求需要经过多少次处理 把这些处理以一个链的形式返回给DispatchServlet 然后DispatchServlet根据这个执行链去调用其他的Servlet来执行处理
  2. 获取到处理器执行链之后 DispatchServlet依次获取处理器适配器 根据适配器找到对应的处理器(就是一个Servlet)来进行处理 并获取返回结果ModelAndView对象 这个对象就是获取的数据
  3. 获取到数据以后 还需要获取页面 所以接来下会调用ViewResolver对象获取页面
  4. 得到页面以后 把之前获取的到的数据填充到页面 并对页面进行渲染
  5. 最后 返回给客户端结果页面

📑总结来说 就是获取数据 + 页面 -> 进行渲染 -> 返回页面(当然 如果请求只需获取数据 那么只需要返回JSON数据就可以了 在Ajax请求中一般要返回JSON数据而不是页面)

🍭源码Debug准备

光有上面的理论是不够的 接下来对源码进行⚡Debug以让理论得到验证

这个验证将会在SpringBoot项目下进行 前提是在Application.yml文件中设置Thymeleaf模板引擎

spring:
  thymeleaf:
    cache: false
    prefix: classpath:/templates/
    suffix: .html # 模板文件名后缀
    encoding: UTF-8
    content-type: text/html
    mode: HTML

web开发依赖

<!-- 导入和web开发相关的所有依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

⚡创建DebugController类

在SpringBoot项目中创建一个新的DebugController 代码如下

package com.xmall.controller;

/**
@author Liu Xianmeng
@createTime 2023/10/13 16:13
@instruction 用于Debug测试 SpringMVC的执行流程
*/
@SuppressWarnings({"all"})
@Controller
public class DebugController {
    @RequestMapping("/debug/getModelAndView")
    public ModelAndView getModelAndView(HttpServletRequest request, HttpServletResponse response) {
        // 创建一个新的ModelANDView对象
        ModelAndView modelAndView = new ModelAndView();
        // 设置视图的名字 这个result.html页面等会就会创建
        modelAndView.setViewName("result");
        // 为modelAndView对象添加一个数据
        modelAndView.addObject("name", "BigBigMeng");
        // 返回modelAndView对象 -> 给客户端(浏览器)
        return modelAndView;
    }
}

⚡创建result.html页面

注意这个页面要放在Application.yml配置的前缀prefix: classpath:/templates/目录下

<!DOCTYPE html>
<!-- 使用Thymeleaf模板引擎 -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>result页面</title>
</head>
<body>
<h1>result页面</h1>
<h2>返回的model信息:<span th:text="${name}"></span></h2>
</body>
</html>

⚡启动项目·执行测试

启动项目

执行测试

🍭源码Debug实战

⚡预备动作

1️⃣首先 全局查找DispatcherServlet类 找到它的doService方法 并打上断点 启动项目

2️⃣浏览器访问

3️⃣查看后端

4️⃣继续添加断点 并放行

5️⃣放行后 看到设置的上下文是一个函数getWebApplicationContext()的返回结果

6️⃣对这个函数进行估值

⚡执行分发操作

7️⃣下一个断点 -> doDispatch 执行分发Servelet

⚡获取到处理器执行链和handlerMapping

8️⃣进入doDispatch方法

⚡获取到handlerAdapter

⚡执行handler方法

9️⃣用反射调用目标方法 进入ha.handle方法

🔟进入handleInternal方法

1️⃣1️⃣进入invokeHandlerMethod方法

1️⃣2️⃣放行

断点回到DebugController类:

1️⃣3️⃣得到ModelAndView对象

⚡返回ModelAndView对象

1️⃣4️⃣继续放行

⚡对页面进行渲染

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    ...
    View view;
    String viewName = mv.getViewName();
    if (viewName != null) {
        // We need to resolve the view name.
        // ⚡⚡⚡执行视图解析
        view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
        if (view == null) {
            throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                    "' in servlet with name '" + getServletName() + "'");
        }
    }
    ...
}

⚡执行视图解析

⚡最后一步 视图渲染

⚡返回页面结果

🍭总结

到此 SpringMVC的执行流程就分析完毕啦~