手写Spring框架---MVC实现

目录

预备

自研框架MVC的实现

MVC架构草图:

大致流程

实现思路

自定义注解

JavaBean

请求的拦截-建立DispatcherServlet

责任链处理请求

RequestProcessor矩阵

Render矩阵


  • 预备

  • 在DispatcherServlet:
    • 解析请求路径和请求方法
    • 依赖容器,建立并维护Controller方法与请求的映射
    • 用合适的Controller方法去处理特定的请求
  • 参照SpringMVC,仅通过DispatcherServlet进行请求派发这样可以让系统模块更加明确,该类的任务有:
    • 拦截全部请求
    • 解析请求
    • 派发给对应的Controller里面进行处理
  • 通过下面的注解可以拦截到全部请求

  • 由于给DispatcherServlet标记了@WebServlet("/"),所以在tomcat启动之后会将DispatcherServlet给加载进来

  • 因为设置了/匹配所有的的url-pattern,而且在tomcat插件中的设置了项目的根路径,<path>/${project.artifactId}</path>可以获取项目的名字,这样设置之后以项目名为根路径的请求都会经由DispatcherServlet来处理,里面的service方法就是用来处理请求的

  • 相关的请求就会交给DispatcherServlet来处理,在DispatcherServlet加载到tomcat里面之后,在首次接收外部请求的时候,会调用里面init方法来完成自身的初始化,初始化之后调用service来处理相关的请求
  • 后续的请求再到来时不会再执行初始化方法,直接调用service方法来处理请求
  • HttpServletRequest里面包含了请求路径和请求方法以及请求里面的业务参数
  • 通过类似简单工厂方法的模式解析请求方法和请求路径,按照请求路径和请求方法转发到对应的controller方法处理
  • 在实际的使用中可以选择将返回的数据转换为json格式返回给前端,或者也可以生成相关的页面视图返回给前端去做渲染
  • 下面的会对jsp请求也会进行拦截,如果我们在页面中转发到jsp,就依然会被拦截到这个类里

  • 原因在tomcat的web.xml中,反斜杠是Servlet中特殊的匹配模式,优先级最低,比*.jsp优先级低,但是反斜杠星号属于路径匹配,优先级比*.jsp高

  • 自研框架MVC的实现

  • MVC架构草图:

  • 大致流程

  • 获取http请求和需要回发的http响应对象,之后将他们委托给RequestProcessorChain处理
  • 我们只处理get和post方法的请求,RequestProcessorChain参照的是责任链模式的后置处理器的处理逻辑,里面保存了处理RequestProcessor接口的多个不同的实现类,之所以会有多个不同的实现类对应为DispatcherServlet是项目里面所有请求的唯一入口
  • DispatcherServlet[ 调度Servlet ]的作用是将请求分发到不同的处理器
  • 这些请求里即会有获取jsp页面的请求,也会有获取静态资源的请求、直接获取json数据的请求等,针对不同的请求会使用不同的RequestProcessor来处理
  • Spring MVC框架像许多其他MVC框架一样,以请求为驱动,围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)

  • 简要分析执行流程
    • 1-DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心
    • 用户发出请求,DispatcherServlet接收请求并拦截请求
    • 假设请求的url为:http://localhost:8080/SpringMVC/hello
    • 如上url拆分成三部分:
      • http://localhost:8080服务器域名
      • SpringMVC部署在服务器上的web站点
      • hello表示控制器
    • 通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器
    • 2-HandlerMapping为处理器映射;DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler
    • 3-HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello
    • 4-HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等
    • 5-HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler
    • 6-Handler让具体的Controller执行
    • 7-Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView
    • 8-HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet
    • 9-DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名
    • 10-视图解析器将解析的逻辑视图名传给DispatcherServlet
    • 11-DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图
    • 12-最终视图呈现给用户
  • 实现思路

    • 自研框架实现思路定义DispatcherServlet分发器
    • 创建责任链对象实例
    • 通过责任链模式来依次调用请求处理对请求进行处理
    • 对处理结果进行渲染
  • 自定义注解

    • @RequestMapping 标识controller的方法和请求路径和请求方法的映射问题

    • @RequestParam 请求方法参数名

    • @ResponseBody 用于标记自动对返回值进行json处理

  • JavaBean

    • ControllerMethod 待执行的Controller及其方法实例和参数的映射

    • ModelAndView 存储处理完后的结果数据以及显示该数据的视图

    • RequestMethod 框架目前支持的请求方法

    • RequestPathInfo 储存http请求路径和请求方法

  • 请求的拦截-建立DispatcherServlet

    • 初始化容器
    • 初始化请求处理器责任链
    • 通过责任链模式来依次调用请求处理器对请求进行处理
    • 对处理结果进行渲染

    • init方法
      • 对常驻变量进行初始化
      • servlet是程序执行的入口:对容器进行初始化并将相关的bean加载进来,同时完成AOP相关逻辑的织入,以及相关的IoC依赖注入等操作
      • 因为后面是采用责任链模式来实现RequestProcessor矩阵的,要将对应的处理器添加到处理器列表中
      • 将RequestProcessor矩阵按序添加到缓存列表里
      • 之所以按照图示的顺序进行添加,是因为我们的请求经过编码和路径的处理之后才能进行后续的处理
      • 将ControllerRequestProcessor放在最后是因为它的处理会比较耗时,需要将请求和controller的方法实例进行匹配
    • service方法
      • 首先创建责任链对象实例
      • 然后通过责任链模式来依次调用请求处理器对请求进行处理
        • 通过迭代器遍历注册的请求处理器实现类列表
        • 直到某个请求处理器执行后返回false为止
        • 期间如果出现异常,则交由内部异常渲染器处理
      • 最后对处理结果进行渲染
        • 如果请求处理器实现类均未选择合适的渲染器,则使用默认的
        • 调用渲染器的render方法对结果进行渲染
  • 责任链处理请求

  • 以责任链的模式执行注册的请求处理器
  • 委派给特定的Render实例对处理后的结果进行渲染

  • RequestProcessor矩阵

    • PreRequestProcessor处理器(请求预处理器):主要负责对请求的编码以及对路径做一些前置处理

    • 剩余的处理器都会去解析请求,以看看请求是否由该处理器去处理的
    • StaticResourceRequestProcessor处理器(静态资源处理器):对静态资源请求

    • 利用的tomcat默认请求派发器RequestDispatcher处理
    • JspRequestProcessor处理器(JSP处理器):对jsp页面的访问请求进行处理(不仅过controller直接访问页面的请求)

    • 利用的tomcat的jspServlet处理
    • ControllerRequestProcessor处理器(Controller处理器):将请求派发到对应的controller方法里面进行处理
      • 针对特定请求,选择匹配的Controller方法进行处理
      • 解析出请求里的参数及其对应的值,并赋值给Controller方法的参数
      • 选择合适的Render,为后续请求处理结果的渲染做准备

      • 建立Controller方法与请求的映射关系
        • 请求中包含的信息有路径和请求参数,所以需要根据这些信息找到对应的Controller方法
        • 利用RequestPathInfo存储请求的信息,ControllerMethod存储Controller以及方法的信息
        • 建立的映射关系就是RequestPathInfo与ControllerMethod的,这样就可以根据请求定位到对应的方法
      • 然后利用ConverterUtil给需要执行的方法参数赋值
      • 最后利用反射执行获取执行的结果,根据结果设置结果渲染器
  • Render矩阵

    • 渲染,处理了相关的请求之后,需要将结果以不同的形式给展现出来,并且处理的过程中可能会出现各种各样的异常,也需要去做体现
    • Render负责对结果进行包装并展现
    • 当处理器处理完之后就会调用特定的实现了Render接口的实现类,对处理结果进行展现

    • DefaultResultRender(默认结果渲染器):当请求处理成功后,用户只需要返回一个成功的状态码
      • 如果请求处理器实现类均未选择合适的渲染器,则使用默认的结果渲染器
      • 主要将处理的结果状态码返回,默认为200

    • JsonResultRender(Json结果渲染器):用户发送的请求是想要获取json格式的返回结果
      • 当方法上面使用@ResponseBody 注解时,利用Gson将结果转换成Json数据返回

    • ViewResultRender(视图解析器):将逻辑视图转换成用户可以看到的物理视图,类似于ModelAndView对象
      • 视图解析器则根据返回结果的不同,而进行跳转
      • 如果是String数据,则创建一个ModelAndView对象,并将数据加入到视图地址
      • 如果是ModelAndView,则会解析其中的视图地址和数据
      • 针对其他情况,则直接抛出异常

    • InternalErrorResultRender(异常结果渲染器):对异常的处理
      • 以责任链的模式处理请求,期间如果出现异常,则交由内部异常渲染器处理
      • 设置状态码500和异常信息

    • ResourceNotFoundResultRende(找不到路径渲染器):资源无法找到的异常
      • 在根据请求路径转发到Controller时,找不到对应的对象或者方法,则使用该渲染器
      • 返回404和请求的路径及方法

  • 测试成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1133.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

水库大坝安全监测系统是由什么组成的?

水库大坝是防洪抗灾的重要设施&#xff0c;它们的安全性直接关系到人民群众的生命财产安全。因此&#xff0c;水库大坝的安全监测必不可少。水库大坝安全监测系统是一种集成了数据采集、传输、处理和分析的技术平台&#xff0c;能够实时、准确地监测大坝的状态&#xff0c;及时…

一.《某三国》人物属性及其相关属性

人物属性 1.找一个可以操控变化的属性来找 比如血量.坐标或者五铢(绑定金币),这里我们用五铢找 五铢只要打一个怪就会加一点 2.我们直接搜变化即可搜到 五铢地址0AD64EAC 3.我们CE给地址下访问 4.这里我们最后找第一条访问 因为他是被改变的 或者你CE给地址下写入 5.然后我…

使用docker-file 将springboot项目打成镜像,发布成容器服务

一 docker-file将jar包发布成容器服务 1.1 docker的安装 [rootlocalhost ~]# uname -r 3.10.0-862.el7.x86_64 [rootlocalhost ~]# yum install docker [rootlocalhost export]# systemctl start docker [rootlocalhost export]# docker -v Docker version 1.13.1, build…

学习react,复制一个civitai(C站)-更新3

更新内容 优化了一下加载速度 图片列表 初步更新了199张图片&#xff0c;大部分都有stable diffusion 的prompts。 可以直接复制到AI绘画里面使用。 先来看看效果图吧&#xff1a; 我还是挺喜欢这种砌砖流布局 技术点 同样使用了砌墙瀑布流布局:masonry js 安装方法 npm …

ios 启动页storyboard 使用记录

本文简单记录ios启动页storyboard 如何使用和注意事项。 xcode窗口简介 以xcode14为例&#xff0c;新建项目如下图&#xff0c;左边文件栏中的LaunchScreen.storyboard 为默认启动页布局。窗口中间部分是storyboard中的组件列表&#xff0c;右侧为预览&#xff0c;可以看到渲…

摩尔投票算法(Moore‘s Voting Algorithm)及例题

摩尔投票算法&#xff08;Moores Voting Algorithm&#xff09;及例题 摩尔投票算法简介摩尔投票算法算法思想摩尔投票算法经典题目169. 多数元素229. 多数元素 II6927. 合法分割的最小下标 上午打力扣第 354 场周赛最后十五分钟用摩尔投票算法直接秒了第三题。 摩尔投票算法简…

【图像处理】基于双目视觉的物体体积测量算法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【QT/OpenCV】QT实现张正友相机标定

相机标定 01、相机标定02、OpenCV函数及其张正友标定法2.1、相机标定步骤2.2、相机标定相关函数2.2.1 提取角点--- findChessboardCorners2.2.2 亚像素角点提取1--- find4QuadCornerSubpix2.2.3 亚像素角点提取2--- cornerSubPix2.2.4 绘制内角点 --- drawChessboardCorners2.2…

生成式AI:大语言模型ChatGPT交互的机制

推荐&#xff1a;将NSDT场景编辑器加入你的3D工具链 3D工具集&#xff1a;NSDT简石数字孪生 与 ChatGPT 有效交互的快速工程 随着生成式人工智能的普及&#xff0c;特别是 ChatGPT&#xff0c;提示已成为人工智能世界中越来越重要的技能。制作提示&#xff0c;与大型语言模型&…

【C语言督学营 第十八天】考研408排序大题初探(将排序思想融入题目)

文章目录 题目一分析代码实战 题目二分析代码实战 补充(快排与归并)数据结构大题注意点&#xff01;&#xff01;&#xff01;(评分标准) 题目一 分析 (1&#xff09;算法的基本设计思想 由题意知&#xff0c;将最小的nl2个元素放在Ai中&#xff0c;其余的元素放在A2中&#x…

Linux信号

文章目录 一.信号基础二.信号的产生1.使用键盘组合键发送信号&#xff08;只能给当前正在运行的进程发&#xff09;信号捕捉2.使用kill指令&#xff08;可以向任意进程发送信号&#xff09;3.使用raise&#xff08;&#xff09;让进程自己给自己发送信号4.硬件异常产生信号a.除…

Java中List的使用方法简单介绍

Java中List的使用方法简单介绍 java中的List就是一种集合对象&#xff0c;将所有的对象集中到一起存储。List里面可以放任意的java对象&#xff0c;也可以直接放值。 使用方法很简单&#xff0c;类似于数组。 使用List之前必须在程序头引入java.util.* import java.util.*; pub…

分享四款导航页 个人主页html源码

一、开源免费&#xff0c;可以展示很多社交账号&#xff0c;也可以更换社交账号图标指向你的网站&#xff0c;上传后即可使用 https://wwwf.lanzout.com/ik7R912s031g 二、开源免费&#xff0c;不过部署稍微麻烦点 https://wwwf.lanzout.com/iCq2u12s02wb 三、适合做成导航页面…

golang网络编程学习-1rpc

网络编程主要的内容是&#xff1a; 1.TCP网络编程 2.http服务 3.rpc服务 4.websocket服务 一、rpc RPC 框架----- 远程过程调用协议RPC&#xff08;Remote Procedure Call Protocol)-----允许像调用本地服务一样调用远程服务。 RPC是指远程过程调用&#xff0c;也就是说两台服…

MySQL结构以及数据管理(增删改查)

目录 1.数据库的简介 2.数据库分类 2.1关系型数据库 2.2 非关系型数据库 3.mysql的数据类型 3.1 常用的数据库类型 4.mysql的数据库结构 4.1 查看库信息 4.2 查看表信息 5.SQL 语句 5.1 SQL语言分类&#xff1a; 1.数据库的简介 数据库&#xff08;database&#…

Spark高级特性

spark shuffle 中 map 和 reduce 是一个相对的概念&#xff0c;map是产生一批数据&#xff0c;reduce是接收一批数据&#xff0c;前一个任务是map&#xff0c;后一个任务是reduce。 hashShuffle&#xff1a;hash分组&#xff0c;一个task里面按hash值的不同&#xff0c;分到不…

微服务优雅上下线的实践方法

导语 本文介绍了微服务优雅上下线的实践方法及原理&#xff0c;包括适用于 Spring 应用的优雅上下线逻辑和服务预热&#xff0c;以及使用 Docker 实现无损下线的 Demo。同时&#xff0c;本文还总结了优雅上下线的价值和挑战。 作者简介 颜松柏 腾讯云微服务架构师 拥有超过…

Flask_实现token鉴权

目录 1、安装依赖 2、实现代码 3、测试 源码等资料获取方法 1、安装依赖 pip install flask pip install pycryptodome 2、实现代码 import random import string import time import base64from functools import wrapsfrom flask import Flask, jsonify, session, req…

RabbitMQ如何保证消息的可靠性6000字详解

RabbitMQ通过生产者、消费者以及MQ Broker达到了解耦的特点&#xff0c;实现了异步通讯等一些优点&#xff0c;但是在消息的传递中引入了MQ Broker必然会带来一些其他问题&#xff0c;比如如何保证消息在传输过程中可靠性&#xff08;即不让数据丢失&#xff0c;发送一次消息就…

学习babylon.js --- [2] 项目工程搭建

本文讲述如何搭建babylonjs的项目工程。 一 准备 首先创建一个目录叫MyProject&#xff0c;然后在这个目录里再创建三个目录&#xff1a;dist&#xff0c;public和src&#xff0c;如下&#xff0c; 接着在src目录里添加一个文件叫app.ts&#xff0c;本文使用typescript&#…