HttpServletBean

HttpServletBean主要参与了创建工作,并没有涉及请求的处理。

FrameworkServlet

FrameworkServlet的service方法里添加了对PATCH的处理,并将所有需要自己处理的请求都集中到了processRequest方法进行统一处理,这和HttpServlet里面根据request的类型将请求分配到各个不同的方法进行处理的过程正好相反。
processRequest方法里主要的处理逻辑交给了doService,这是一个模板方法,在子类DispatcherServlet实现。

DispatcherServlet

DispatcherServlet的doServic并没有直接进行处理,而是交给了doDispatch进行具体的处理;在doDispatch处理前doServic做了一些事情,判断是不是include请求,如果是则对request的Attribute做个快照备份,等doDispatch处理完之后进行还原。

doDispatch的核心代码
// 根据request找到Handler
mappedHandler = getHandler(processedRequest);
// 根据Handler找到对应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 用HandlerAdapter处理Handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 处理上面的结果,包含找到View并渲染输出给用户
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

Handler:处理器,对应MVC中的Controller层,它可以是类,也可以是方法;标注了@RequestMapping的方法就是一个Handler。
HandlerMapping:用来查找Handler
HandlerAdapter:Spring MVC中的Handler可以是任意的形式,只要能处理请求就OK,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。HandlerAdapter让固定的Servlet处理方法可以调用灵活的Handler来处理请求。

源码分析:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 请求对象,如果是上传请求会封装为上传类型的request
HttpServletRequest processedRequest = request;
// 处理器链,包含处理器和Interceptor
HandlerExecutionChain mappedHandler = null;
// 是不是文件上传
boolean multipartRequestParsed = false;
// 异步管理
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
try {
ModelAndView mv = null;
// 异常对象
Object dispatchException = null;
try {
//如果是上传请求,将request转换为MultipartHttpServletRequest,用到了MultipartResolver
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 根据request找到处理器链,其中包含与当前request相匹配的Interceptor和handler
// Interceptor和Handler,执行时先调用Interceptor的preHandle方法,最后执行Handler
// 返回的时候按相反的顺序执行Interceptor的postHandle方法
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// 根据Handler找到对应的HandlerAdapter
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
/* 处理Get、Head请求的LastModified
* 当浏览器第一次跟服务器请求资源(GET、Head请求)时,
* 服务器在返回的请求头里面会包含一个Last-Modified的属性,
* 代表本资源最后是什么时候修改的。
* 在浏览器以后发送请求时会同时发送之前接收到的LastModified,
* 服务器接收到带Last-Modified的请求后会用其值和自己实际资源的最后修改时间做对比,
* 如果资源过期了则返回新的资源(同时返回新的Last-Modified),
* 否则直接返回304状态码表示资源未过期,浏览器直接使用之前缓存的结果。
*/
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
} if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
/* 接下来依次调用相应Interceptor的preHandle、
* HandlerAdapter使用Handler处理请求,Controller就是在这个地方执行的,
* Handler处理完请求后,如果需要异步处理,则直接返回,
* 如果不需要异步处理,当view为空时(如Handler返回值为void),
* 设置默认view,然后执行相应Interceptor的postHandle。
*/
// 执行相应的Interceptor的preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// HandlerAdapter使用Handler处理请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 如果需要异步处理直接返回
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 当view为空时,比如,Handler返回值为void,根据request设置默认的view
this.applyDefaultViewName(processedRequest, mv);
// 执行相应Interceptor的方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 处理返回结果。包括处理异常、渲染页面、发出完成通知触发Interceptor的afterCompletion
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
} } finally {
// 判断是否执行异步请求
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
// 删除上传请求的资源
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
} }
}

SpringMVC处理请求的更多相关文章

  1. SpringBoot对比SpringMVC,SpringMVC 处理请求过程

    (问较多:1.SpringBoot对比SpringMVC.2.SpringMVC 处理请求过程.问:springboot的理解 Spring,Spring MVC,Spring Boot 三者比较 S ...

  2. springMvc REST 请求和响应

    前言: 突然怎么也想不起来  springMvc REST 请求的返回  类型了!   (尴尬+究竟)  然后本着 方便的想法 百度了一下 发现了个问题,大家在写      springMvc RES ...

  3. SpringMvc Controller请求链接忽略大小写(包含拦截器)及@ResponseBody返回String中文乱码处理

    SpringMvc Controller请求链接忽略大小写(包含拦截器)及@ResponseBody返回String中文乱码处理... @RequestMapping(value = "/t ...

  4. SpringMVC之请求参数的获取方式

    转载出处:https://www.toutiao.com/i6510822190219264516/ SpringMVC之请求参数的获取方式 常见的一个web服务,如何获取请求参数? 一般最常见的请求 ...

  5. Springmvc Get请求Tomcat、WebLogic中文乱码问题

    Springmvc Get请求Tomcat.WebLogic中文乱码问题 学习了:http://www.cnblogs.com/qingdaofu/p/5633225.html http://www. ...

  6. 16 SpringMVC 的请求参数的绑定与常用注解

    1.SpringMVC 绑定请求参数 (1)支持的数据类型 基本类型参数: 包括基本类型和 String 类型POJO 类型参数: 包括实体类,以及关联的实体类数组和集合类型参数: 包括 List 结 ...

  7. Spring系列 SpringMVC的请求与数据响应

    Spring系列 SpringMVC的请求与数据响应 SpringMVC的数据响应 数据响应的方式 y以下案例均部署在Tomcat上,使用浏览器来访问一个简单的success.jsp页面来实现 Suc ...

  8. SpringMVC探秘-请求之路

    SpringMVC探秘-请求之路 开始 今天来分析一下SpringMVC的原理,探究SpringMVC如何把请求传递到每个Controller的方法上,从Servlet到Controller,一个请求 ...

  9. SpringMVC RequestMapping & 请求参数

    SpringMVC 概述 Spring 为展现层提供的基于 MVC 设计理念的优秀的Web 框架,是目前最主流的 MVC 框架之一 Spring3.0 后全面超越 Struts2,成为最优秀的 MVC ...

  10. SpringMVC处理请求流程

    SpringMVC核心处理流程: 1.DispatcherServlet前端控制器接收发过来的请求,交给HandlerMapping处理器映射器 2.HandlerMapping处理器映射器,根据请求 ...

随机推荐

  1. Java匹马行天下之JavaSE核心技术——面向对象

    面向对象 注: 看此篇时强烈建议有一定的面向对象思想基础,有一定的基础后先翻到下面看第九条:      9.面向对象: 从未封装→封装→继承→多态→抽象类→接口的代码演变 按这个逻辑去看,,哪有不理解 ...

  2. linux下静态链接库和动态链接库

    关于链接库的知识,网上太多资料了,但是并不代表我很熟悉.今天遇到了 一个问题,就是由于静态链接库和ubuntu系统不兼容导致的,虽然花了点时间才搞定 但是,其中暴露的问题也不少. 没有区分好静态链接库 ...

  3. mysql之UPDATE,SELECT,INSERT语法

    一 :UPDATE语法   UPDATE 是一个修改表中行的DML语句. #单表语法(常用) UPDATE [LOW_PRIORITY] [IGNORE] table_reference SET as ...

  4. python函数练习——个人信息修改

    修改个人信息程序 在一个文件里存多个人的个人信息,如以下 1.输入用户名密码,正确后登录系统 ,打印 1. 修改个人信息 2. 打印个人信息 3. 修改密码 2.每个选项写一个方法 3.登录时输错3次 ...

  5. [Leetcode]394.字符串解码

    题目与解释 给定一个经过编码的字符串,返回它解码后的字符串. 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次.注意 k 保证为正 ...

  6. mysql 开发进阶篇系列 25 数据库RPM安装目录介绍

    一.概述 mysql可以在多个平台上运行,在windows平台上安装有noinstall包和图形化包二种方式.在linux/unix平台上有RPM包安装,二进制包(Binary Package)安装, ...

  7. C# sqlhelper 2

    using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Secu ...

  8. Java 8 新特性-菜鸟教程 (5) -Java 8 Stream

    Java 8 Stream Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据. Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种 ...

  9. spring-boot-2.0.3启动源码篇 - 阶段总结

    前言 开心一刻 朋友喜欢去按摩,第一次推门进来的是一个学生美眉,感觉还不错:后来经常去,有时是护士,有时是空姐,有时候是教师.昨天晚上推门进去的是一个女警察,长得贼好看,身材也很好,朋友嗷的一声就扑上 ...

  10. DenseNet 论文阅读笔记

    Densely Connected Convolutional Networks 原文链接 摘要 研究表明,如果卷积网络在接近输入和接近输出地层之间包含较短地连接,那么,该网络可以显著地加深,变得更精 ...