springMVC 请求流程解析

news/2024/11/15 13:44:19/文章来源:https://www.cnblogs.com/jichenghui/p/18353250

`
@SuppressWarnings("deprecation")
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 实际处理时用的请求,如果不是上传请求,则直接使用接收到的 request,否则封装成上传的 request
HttpServletRequest processedRequest = request;
// 处理请求的处理器链(包括处理器和对应的 interceptor)
HandlerExecutionChain mappedHandler = null;
// 上传标志
boolean multipartRequestParsed = false;

	// 获取异步处理器WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;try {// 检查是否是上传请求// 如果是上传请求,则将其封装成 multipartRequestParsed// 内有九个组件之一 MultipartResolverprocessedRequest = checkMultipart(request);// 上传请求标志位// 通过对象是否更改过进行判断multipartRequestParsed = (processedRequest != request);// Determine handler for the current request.// 获得请求对应的 HandlerExecutionChain 对象(HandlerMethod(Controller 的具体方法) 和 HandlerInterceptor 拦截器们)// 重要 拦截器链// 循环遍历三个 HandlerMapping 进行匹配mappedHandler = getHandler(processedRequest);// 获取不到控制器if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request.// 通过适配器的方式进行调用,因为有多个选择。// 根据// 获取与当前 handler 匹配的 Adapter// 重要HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.// 处理GET、HEAD请求的Last-Modified,当浏览器第一次跟服务器请求资源时,服务器会在返回的请求头里包含一个 last_modified 的属性,// last_modified 代表资源最后时什么时候修改的,在浏览器以后发送请求的时候,会同时发送之前接收到的 Last_modified .服务器接收到带last_modified的请求后,// 会跟实际资源的最后修改时间做对比,如果过期了返回新的资源,否则直接返回304表示未过期,直接使用之前缓存的结果即可// 获取请求方式String method = request.getMethod();boolean isGet = HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {// 为了减少资源重复获取long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}// 执行响应的 Interceptor 的 PreHandle// 注意:该方法如果有一个拦截器的前置处理器返回 false,则开始倒序触发所有的拦截器的已完成处理// mappedHandler 是 HandlerExecutionChain// 重要if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// Actually invoke the handler.// mv ModelAndView// 使用适配器执行 handler,并返回视图// 重要// AbstractHandlerMethodAdaptermv = ha.handle(processedRequest, response, mappedHandler.getHandler());// 如果有异步处理if (asyncManager.isConcurrentHandlingStarted()) {return;}// 如果 view 为空,根据 request 设置默认的 view// 默认名字为 请求路径名。// 组件:RequestToViewNameTranslatorapplyDefaultViewName(processedRequest, mv);// 重要  拦截器的后置处理器mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new ServletException("Handler dispatch failed: " + err, err);}// 重要// 处理返回结果,包括处理异常,页面渲染processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {triggerAfterCompletion(processedRequest, response, mappedHandler,new ServletException("Handler processing failed: " + err, err));}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionif (mappedHandler != null) {// 触发 Interceptor 的 afterCompletionmappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}
}`

1.getHandel()
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { // 默认有三个 for (HandlerMapping mapping : this.handlerMappings) { // BeanNameUrlHandlerMapping 第一次 匹配不到 // RequestMappingHandlerMapping - 第二个 通过@Controller生成的 HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }

通过断点可以看到默认会有两个HandlerMapping的实现:RequestMappingHandlerMapping和BeanNameUrlHandlerMapping;
所有加了@Controller的Controller对象会放在RequestMappingHandlerMapping的父类
HandlerExecutionChain即为控制器与连接器

2.由于SpringMVC提供了4种类型的HandlerAdapter,并且他们没有统一的调用接口,所以需要通过适配器来使用。同样适配器的类型也有4种。如下所示:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
支持当前Handler类型的适配器并返回
3.执行 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());,
4.执行响应的interceptor的postHandler方法
查找视图,并相应View

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

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

相关文章

时间分辨率、采样率与采样深度三者关系理解

在脑成像研究中,分辨率和采样率是一个经常被提及的概念,但分辨率和采样率有时候容易混淆。除此之外,采样深度这个重要的概念却很少被提及。因此,本篇随笔主要内容是为阐述上述三者的概念以及相关联系。 概念的明晰 了解关系之前,首先需要明晰三者的定义概念,其中分辨率仅…

SciTech-BigDataAIML-Algorithm-: 主观经验:先验概率似然概率 和 客观事实:后验概率条件概率 + Floyd(弗落伊得)最短路线算法

主观经验 和 客观事实:后验概率 Subjective主观经验: 先验概率 & 似然概率 Objective客观事实: 后验概率 & 条件概率Floyd(弗落伊得)最短路线算法

动手做科研-day01-AI的最新进展与科研应用

01. Python 程序运行工具以及环境搭建 选择使用kaggle官方的notebook作为环境搭建的平台, 因为之前使用过kaggle进行注册,因此直接简单登录,按照下图依次进行操作 note: 需要挂来登录 1. 点击create2. 创建notebook记事本3. 尝试写一个简单的hello world 先新建codeprint(&q…

FFmpeg开发笔记(四十六)利用SRT协议构建手机APP的直播Demo

​不管是传统互联网还是移动互联网,实时数据传输都是刚需,比如以QQ、微信为代表的即时通信工具,能够实时传输文本和图片。其中一对一的图文通信叫做私聊,多对多的图文通信叫做群聊。除了常见的图文即时通信,还有实时音视频通信,比如一对一的音频通话、一对一的视频通话等…

电容在电路中的作用

电容在电路中的作用上图中,六个电容的作用 1、在运算放大器IC供电旁边的电解电容或固态电容C09 一般放在这里的作用是 a.电源输入的电池泵,因为开关电源或者DC/DC离运算放大器IC太远了,相当于中转的电池泵的作用 b.电容的容量较大,所以有低频滤波的效果 2、小电容或者陶瓷电…

基于模糊pid的两路交错boost变换器Simulink仿真及代码自动生成(上)电路仿真部分

设计两路交错BOOST变换电路,搭建Simulink仿真模型,并设计控制算法(常规PID与模糊控制PID)。基于德州仪器TMS320F280025单片机使用Matlab Code Generation Tools进行编程与实物测试。后半部分已更新 简介:设计两路交错BOOST变换电路,搭建Simulink仿真模型,并设计控制算法…

国内IT行业67家外包公司,有多少程序员在里面待过?

之前写过一篇关于外包公司的文章, 《什么是软件外包公司?要不要去外包公司?》 很多粉丝看了后,感觉都在说自己, 存在即合理, 外包大幅度降(可)低(以)了(压)用(榨)人(更)成(多)本(人), 降低了用(不)人(怕)风(裁)险(人)。 正式员工多了一些保障和一…

横扫鸿蒙弹窗乱象,SmartDialog出世

前言 但凡用过鸿蒙原生弹窗的小伙伴,就能体会到它们是有多么的难用和奇葩,什么AlertDialog,CustomDialog,SubWindow,bindXxx,只要大家用心去体验,就能发现他们有很多离谱的设计和限制,时常就是一边用,一边骂骂咧咧的吐槽 实属无奈,就把鸿蒙版的SmartDialog写出来了 f…

XSS 专项

访问web应用,首页HTML发现新端点如下:使用《赏猎技战法》https://www.cnblogs.com/sec875/p/18335838 中的 测试 XSS 流程,使用一个良性payload试试水:<h1>666 同时思考此处的功能点:https://cfceb12f2bfd-sec875.a.barker-social.com/post/1 post作为输入时和1作为…

Skeleton Recall Loss 分割领域的新突破:极大的减少了资源消耗,还能提高性能

精确分割在当今众多领域都是一项关键需求比如说自动驾驶汽车的训练、医学图像识别系统,以及通过卫星图像进行监测。在许多其他领域,当感兴趣的对象微小但至关重要时,例如研究血管流动、手术规划、检测建筑结构中的裂缝或优化路线规划,需要更高的精度。此前已经做了大量工作…

Unity脚本生命周期

生命周期函数的概念 所有继承MonoBehavior的脚本,最终都会挂在到GameObject游戏对象上 生命周期函数,就是该脚本对象依附的GameObject对象从出生到消亡整个生命周期中 会通过反射自动调用一些特殊函数 Unity帮助我们记录了一个GameObject对象依附了哪些脚本 会自动的得到这些…