spring高级篇(八)

本篇对Spring MVC 的执行流程做一个简单总结

MVC执行流程总结

        当浏览器发送一个请求,例如http://localhost:8080/hello,请求到达服务器后,一般会进行如下操作:

        1、首先会经过DispatcherServlet,默认映射路径为 /,即会匹配到所有请求 URL,可作为请求的统一入口,也被称之为前控制器(jsp 不会匹配到 DispatcherServlet )

        非Spring Boot 程序,需要手动进行创建,此前的案例中已多次演示:

   /*** 创建DispatcherServlet* @return*/@Beanpublic DispatcherServlet dispatcherServlet(){return new DispatcherServlet();}

        Spring Boot 程序,由 DispatcherServletAutoConfiguration 进行自动装配:

        DispatcherServlet默认是在首次使用时,由tomcat容器初始化,也可以进行设置setLoadOnStartup() 为启动时初始化:

    /*** 注册DispatcherServlet springmvc入口* @param dispatcherServlet* @return*/@Beanpublic DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet,WebMvcProperties webMvcProperties){DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, "/");//设置tomcat容器启动时即进行DispatcherServlet初始化registrationBean.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());return registrationBean;}

        DispatcherServlet 初始化时会优先到容器里寻找各种组件,作为它的成员变量:

        下面的init方法有一个共同点:首先会去父子容器中寻找有无相关组件,如果没有会使用默认的组件:

  • HandlerMapping :初始化时记录映射关系。(初始化时,会收集所有映射信息,封装为 Map)
  • HandlerAdapter :初始化时准备参数解析器、返回值处理器、消息转换器 。(分派请求)
  • HandlerExceptionResolver :初始化时准备参数解析器、返回值处理器、消息转换器。(处理异常)
  • ViewResolver :准备视图处理

        容器初始化时,会收集所有 @RequestMapping 映射信息,封装为 Map:

//        RequestMappingHandlerMapping 初始化时,会收集所有 @RequestMapping 映射信息,封装为 Map
//        k:请求方式 路径{ /test4}  v 方法信息com.itbaima.a18.Controller1#test4()Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();handlerMethods.forEach((k,v)->{System.out.println( k + "=" + v);});

       2、DispatcherServlet 会利用HandlerMapping 的实现去查找控制器方法,我们使用最常用的 RequestMappingHandlerMapping 举例:

  • 根据 /hello 路径找到 @RequestMapping("/hello") 对应的控制器方法
  • 控制器方法会被封装为 HandlerMethod 对象,并结合匹配到的拦截器一起返回给 DispatcherServlet
  • HandlerMethod 和拦截器合在一起称为 HandlerExecutionChain(调用链)对象
//发送请求了,根据路径K 获取RequestMappingHandlerMapping  封装的 Map 对应的V HandlerMethod
//获取的结果会包装在拦截器链中
//HandlerExecutionChain with [com.itbaima.a18.Controller1#test1()] and 0 interceptors
HandlerExecutionChain chain = handlerMapping.getHandler(request);

       3、DispatcherServlet 接下来会:

        调用拦截器的 preHandle 方法:如果与preHandle方法中定义的拦截规则不匹配,就直接返回错误信息,不再向下执行。

        RequestMappingHandlerAdapter 调用 handle 方法,准备数据绑定工厂、模型工厂、ModelAndViewContainer、将 HandlerMethod 完善为 ServletInvocableHandlerMethod:

  • @ControllerAdvice 全局增强点1️:补充模型数据,通过解析@ModelAttribute  标注的方法补充模型数据到container中。
    @ControllerAdvicestatic class MyControllerAdvice {@ModelAttribute("a")public String aa() {return "aa";}}/*** ModelAttribute注解加在参数上,由参数解析器负责解析* 加在方法上,由HandlerAdapt进行解析*/@Controllerstatic class Controller1 {@ResponseStatus(HttpStatus.OK)public ModelAndView foo(@ModelAttribute("u") User user) {System.out.println("foo");return null;}}
  • @ControllerAdvice 全局增强点2:补充自定义类型转换器,通过@InitBinder 注解标记一个用于初始化DataBinder对象,自定义数据绑定行为的方法,它会在控制器处理请求之前被调用。(如果@InitBinder注解加在被@ControllerAdvice 注解标记的控制器类的方法中时,其作用范围是全局的,并且是由RequestMappingHandlerAdapter 在初始化时解析并记录。而@InitBinder 注解加在被@Controller 标记的控制器中的方法上时,会在控制器方法首次执行时解析并记录。
    @ControllerAdvicestatic class MyControllerAdvice {@InitBinderpublic void binder3(WebDataBinder webDataBinder) {webDataBinder.addCustomFormatter(new MyDateFormatter("binder3 转换器"));}}@Controllerstatic class Controller1 {@InitBinderpublic void binder1(WebDataBinder webDataBinder) {webDataBinder.addCustomFormatter(new MyDateFormatter("binder1 转换器"));}public void foo() {}}

        RequestMappingHandlerAdapter中有两个成员变量:

  • private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache:用于存储被@ControllerAdvice标记的控制器中 @InitBinder 标注的方法。
  • private final Map<Class<?>, Set<Method>> initBinderCache:用于存储@Controller 标记的控制器中@InitBinder标注的方法。


        然后会使用 HandlerMethodArgumentResolver 准备参数

  • @ControllerAdvice 全局增强点3:RequestBody 增强        

        调用 ServletInvocableHandlerMethod 、使用 HandlerMethodReturnValueHandler 处理返回值。

  • @ControllerAdvice 全局增强点4:ResponseBody 增强

        ResponseBody返回响应体前包装:

    @ControllerAdvicestatic class MyResponseAdvice implements ResponseBodyAdvice<Object> {/*** 支持的方法** @param returnType    返回值类型* @param converterType 转换类型* @return*/@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {//如果方法上加了ResponseBody注解,或者类上加了ResponseBody/RestController注解,才进行转换if (returnType.getMethodAnnotation(ResponseBody.class) != null|| AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null) {return true;}return false;}/*** 增强的逻辑** @param body                  返回值* @param returnType            返回类型* @param selectedContentType   所选的响应内容类型。* @param selectedConverterType 所选的消息转换器类型。* @param request               当前的请求对象。* @param response              当前的响应对象。* @return*/@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {//如果返回值就是Result类型则直接返回if (body instanceof Result) {return body;}//否则包装成Result类型返回return Result.ok(body);}}

        最后会根据 ModelAndViewContainer 获取 ModelAndView:

  • 返回值处理器调用了 HttpMessageConverter 来将结果转换为 JSON,这时 ModelAndView 就为 null
  • 如果返回的 ModelAndView 为 null,不会进行后续的视图渲染与解析。

        ModelAndView、String、未被@ResponseBody 注解控制的对象类型返回值(无论是否显式声明了@ModelAttribute),都要经历视图渲染的过程。

        ModelAndView找视图,是根据ModelAndView构造中的viewName寻找同名的视图,还会使用.addObject() 方法中指定的数据对视图进行渲染 。

        如果没有指定视图名,则会:

        根据请求路径推断视图名: 如果在处理器方法中没有显式指定视图名,Spring MVC 会根据请求路径来推断视图名。
         根据返回值类型推断视图名: 如果处理器方法的返回值类型是String类型,并且没有使用 @ResponseBody 注解,Spring MVC 会将返回的字符串作为视图名处理。
        默认视图名: 如果以上两种方式都没有找到视图名,Spring MVC 会使用默认的视图名。默认的视图名通常是处理器方法所在的类名转换而来,再加上适当的前后缀。

        String找视图,是根据返回值的名称去找同名的视图。

        未被@ResponseBody 注解控制的对象类型返回值,找视图时,如果方法上使用 @RequestMapping("/") 及其派生注解声明了路径,则按照路径的值去匹配视图。如果没有,则需要手动指定路径。

        HttpEntity、HttpHeaders、加上了@ResponseBody 注解的对象返回值类型,因为对应解析器的handleReturnValue 方法中标记了请求已经被处理,无需继续渲染视图,所以不走渲染视图流程。其区别在于返回的响应头和响应体的完整性。

4、调用拦截器的 postHandle 方法

5、处理异常或视图渲染

  •  @ControllerAdvice 全局增强点5️:@ExceptionHandler 异常处理

6、调用拦截器的 afterCompletion 方法

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

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

相关文章

GRU模块:nn.GRU层的输出state与output

在 GRU&#xff08;Gated Recurrent Unit&#xff09;中&#xff0c;output 和 state 都是由 GRU 层的循环计算产生的&#xff0c;它们之间有直接的关系。state 实际上是 output 中最后一个时间步的隐藏状态。 GRU 的基本公式 GRU 的核心计算包括更新门&#xff08;update gat…

用于密集预测任务的通道知识蒸馏——关键字:蒸馏

摘要 https://arxiv.org/pdf/2011.13256 知识蒸馏(KD)已被证明是训练紧凑密集预测模型的简单有效工具。通过从大型教师网络转移而来的额外监督来训练轻量级学生网络。大多数先前的针对密集预测任务的KD变体都在空间域中对学生网络和教师网络的激活图进行对齐,通常是通过在每…

【Linux】进程间通信 - 管道

文章目录 1. 进程间通信介绍1.1 进程间通信目的1.2 进程间通信发展1.3 进程间通信分类 2. 管道2.1 什么是管道2.2 匿名管道2.3 用 fork 来共享管道原理2.4 站在文件描述符角度 - 深入理解管道2.5 站在内核角度 - 管道本质2.6 管道读写规则2.7 管道特点 3. 命名管道3.1 匿名管道…

linux代码实操——信号的使用

信号的基本概念 信号是系统响应某个条件而产生的事件&#xff0c;进程接收到信号会执行相应的操作。 与信号有关的系统调用在“signal.h”头文件中有声明 常见信号的值&#xff0c;及对应的功能说明&#xff1a; 修改信号的响应方式 – signal() 我们来做个小实验: 在键盘上…

推荐书单|提升境界、思维能力

1、《别做正常的傻瓜》 豆瓣评分&#xff1a;8.1 通过揭示人们在日常生活中常见的非理性行为&#xff0c;引导读者认识并克服这些行为&#xff0c;从而做出更明智的决策。 2、《活法》 豆瓣评分&#xff1a;8.1 稻盛和夫分享其人生哲学和经营哲学的著作&#xff0c;强调了正确…

软设之段页式存储

页式存储&#xff1a;将程序与内存划分为同样大小的块&#xff0c;以页为单位将程序调入内存。 比如说每页是1M&#xff0c;不管是内存还是程序&#xff0c;每页都是1M 高级程序语言使用逻辑地址&#xff0c;比如C语言用的指针。 运行状态时&#xff0c;内存中使用物理地址。…

【C++】模板初阶:泛型编程的起点

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

富文本编辑器CKEditor4简单使用-08(段落首行缩进插件 + 处理粘贴 Microsoft Word 中的内容后保持原始内容格式(包括首行缩进))

富文本编辑器CKEditor4简单使用-08&#xff08;段落首行缩进插件 处理粘贴 Microsoft Word 中的内容后保持原始内容格式&#xff08;包括首行缩进&#xff09;&#xff09; 1. 缩进&#xff0c;特殊方式处理——修改原工具栏里的增加缩进量2 缩进&#xff0c;插件处理2.1 下载…

并查集~~

值为v的数封为Node型的节点&#xff0c;除了nodes中保存了V和Node的对应关系外&#xff0c;并查集相关的parents&#xff0c;sizeMap都是用Node来关联的。 #include<iostream> #include<map> #include<vector> #include<stack> using namespace std;t…

建一个wordpress外贸独立站的费用构成与分析

外贸独立站因为独特的优势&#xff0c;越来越被做外贸的跨境电商所青睐。简站主题经常接到做外贸的老板咨询&#xff0c;建一个wordpress外贸独立站大约多少钱&#xff0c;也是被问的最多的问题之一。下面小简就从几个方面讲一下&#xff0c;决定一个wordpress外贸独立站的费用…

TypeScript的使用:可以谈谈TypeScript的优点以及如何在实际项目中引入和使用TypeScript,包括一些基本的语法和编程技巧。

TypeScript是JavaScript的一个超集&#xff0c;它主要提供了类型系统和对ES6的兼容。下面是一些TypeScript的主要优点&#xff1a; 静态类型检查&#xff1a;这是TypeScript最主要的功能&#xff0c;它可以在编译阶段发现和报告错误&#xff0c;帮助开发者提前找到问题。更好的…

TensorFlow轻松入门(二)——小案例:ANN构建一个或运算的模型

或运算&#xff1a; 位与位进行比较&#xff0c;如果有任一个是1&#xff0c;结果为1&#xff1b;两个都为0&#xff0c;结果则为0。 实现步骤 构建Feature与Label数据 创建顺序模型 指定模型的第一层&#xff0c;线性模型 添加一层激活函数 模型编译 模型训练 模型预测…

GitHub 异常——无法连接22端口:Connection timed out

GitHub 异常——无法连接22端口&#xff1a;Connection timed out 问题描述原因分析&#xff1a;解决方案&#xff1a;参考 问题描述 正常配置并使用使用SSH方式&#xff0c;使用以下命令git clone、git pull、git push&#xff0c;报错如下&#xff1a; ssh: connect to host …

C语言-链表实现贪吃蛇控制台游戏

使用C语言和链表实现贪吃蛇游戏 一、引言 贪吃蛇游戏是一个经典的游戏&#xff0c;它的玩法简单而富有挑战性。在这个博客中&#xff0c;我将分享如何使用C语言和链表数据结构来自主实现贪吃蛇游戏。我会详细介绍游戏的设计思路、编码过程、遇到的问题及解决方案&#xff0c;…

翻译《The Old New Thing》 - Why does the CreateProcess function do autocorrection?

Why does the CreateProcess function do autocorrection? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20050623-03/?p35213 Raymond Chen 在 2005 年 6 月 23 日 为什么 CreateProcess 函数会进行自动更正&#xff1f; 译注&#xff…

【华为OD机试C卷D卷】符号运算(C++/Java/Python)

【华为OD机试】-(A卷+B卷+C卷+D卷)-2024真题合集目录 【华为OD机试】-(C卷+D卷)-2024最新真题目录 题目描述 给定一个表达式,求其分数计算结果。 表达式的限制如下: 所有的输入数字皆为正整数(包括0) 仅支持四则运算(+-*,/)和括号 结果为整数或分数,分数必须化为最简格…

13_Scala面向对象编程_伴生对象

文章目录 1.伴生对象1.1 scala的一个性质&#xff0c;scala文件中的类都是公共的&#xff1b;1.2 scala使用object关键字也可以声明对象&#xff1b; 3.关于伴生对象和类4.权限修饰符&#xff0c;scala仅有private;5.伴生对象可以访问伴生类中的私有属性&#xff1b;6.案例7.伴…

世界十大最具影响力人物颜廷利:真正的高人,靠谱的行为

对于真正的‘高人’&#xff0c; 在面对‘狗洞’时&#xff0c; 他们都比较理智&#xff0c; 从来都不趾高气扬&#xff0c; 因为他们晓得&#xff0c; 倘若说不能弯下腰&#xff0c; 并而直立着身子走路的话&#xff0c; 那么&#xff0c; 他们就不是纯粹的‘高人’&#xff0…

华为OD机试题:字符串变换最小字符串

题目描述&#xff1a; 给定一个字符串s&#xff0c;最多只能进行一次变换&#xff0c;返回变换后能得到的最小字符串&#xff08;按照字典序进行比较&#xff09;。 变换规则&#xff1a;交换字符串中任意两个不同位置的字符。 一串小写字母组成的字符串s 输出描述 按照要求进…

启程Python机器学习之旅:从JupyterLab到神经网络初探

引言 在数据科学和人工智能的浪潮中&#xff0c;Python已经成为最受欢迎的编程语言之一。其简洁的语法和强大的库支持&#xff0c;使得从科研到商业的各个领域都能见到Python的身影。今天&#xff0c;我们将通过JupyterLab——一个交互式的开发环境&#xff0c;开始我们的Pyth…