Spring Web http request请求流程:

首先介绍这边你需要知道的继承体系,DispacherServlet继承自FrameworkServlet,FrameworkServlet继承自HttpServletBean,HttpServletBean继承自HttpServlet,HttpServlet继承自GenericServlet,GenericServlet实现Servlet、ServletConfig接口,我们的流程从请求进入到GenericServlet的service方法开始说起。
  • 拦截器是在DispacherServlet的doDispatch方法中执行的,(url拦截器和用户自定义的其他业务拦截器)

流程总览:

容器监听端口,接收到请求后调用Servlet的service方法,

在service方法中判断用户使用的是get还是post请求,决定后续调用对应的doGet/doPost方法,

在doGet/doPost方法中执行processRequest方法,

processRequest方法执行请求上下文的初始化过程,

然后调用doService()方法,

由该doService方法执行doDispatch方法,

最后由doDispatch方法去获取请求的mappedHandler和HandlerAdapter,处理完用户请求之后通过新建一个ServletWebRequest来渲染返回数据

首先调用GenericServlet的service()方法,源码如下:
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
事实上GenericServlet的service()方法是一个抽象方法,而HttpServlet继承了GenericServlet,所以此处实际调用了HttpServlet的service方法,HttpServlet的service方法源码如下: public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
this.service(request, response);
} else {
throw new ServletException("non-HTTP request or response");
}
}
首先判断ServletRequest、ServletResponse是否是标准的HttpServletRequest、HttpServletResponse,如果不是则抛出ServletException异常,否则继续调用实现类的service()方法
对源码做debug我们知道,this.service(request, response);执行到spring FrameworkServlet的service方法。
在spring框架中,FrameworkServlet继承自HttpServletBean,HttpServletBean是一个抽象类,HttpServletBean继承自HttpServlet。
所以HttpServlet的service方法中调用的this.service(request, response);其实是执行的是FrameworkServlet中的service方法。继续看源码:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
super.service(request, response);
} else {
this.processRequest(request, response);
} }
我们的HttpMethod 应该是POST或者GET方法,所以执行super.service(request, response);回到HttpServlet的service(HttpServletRequest req, HttpServletResponse resp)方法:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
我们一GET请求为例,直接看this.doGet(req, resp);回到FrameworkServlet的doGet方法:
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
执行processRequest方法:
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = this.buildLocaleContext(request);//此处调用其实现类的buildLocaleContext方法,spring中即DispatcherServlet,来创建localeContext 对象
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//注册拦截器registerCallableInterceptor
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
//初始化应用context
this.initContextHolders(request, localeContext, requestAttributes); try {
this.doService(request, response);
} catch (ServletException var17) {
failureCause = var17;
throw var17;
} catch (IOException var18) {
failureCause = var18;
throw var18;
} catch (Throwable var19) {
failureCause = var19;
throw new NestedServletException("Request processing failed", var19);
} finally {
this.resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
} if (this.logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", (Throwable)failureCause);
} else if (asyncManager.isConcurrentHandlingStarted()) {
this.logger.debug("Leaving response open for concurrent processing");
} else {
this.logger.debug("Successfully completed request");
}
} this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
} }
可以看到,在FrameworkServlet的processRequest方法中执行了一系列的初始化操作,然后调用this.doService(request, response);也就是调用DispatcherServlet的doService方法
来看DispatcherServlet的doService方法的源码:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//省略掉一些request属性的代码
try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
该方法中主要完成一些request的属性设置,然后this.doDispatch(request, response);源码如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
try {
ModelAndView mv = null;
Object dispatchException = null; try {
//处理multipart 请求
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//从容器中获取mappedHandler
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// 从容器中获取适配器HandlerAdapter 。这个过程中,会调用MappedInterceptor的matches方法,以此来判断次url是否在拦截范围内
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
//处理get请求
if (isGet || "HEAD".equals(method)) {
//lastModified最后修改时间 此处返回-1
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;
}
}
//执行拦截器中的preHandle拦截方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//执行用户controller中对应的业务
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//渲染默认的mv
this.applyDefaultViewName(processedRequest, mv);
//执行PostHandle拦截方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//渲染返回值
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);
} }
}

Spring 框架中Http请求处理流程的更多相关文章

  1. 细说shiro之五:在spring框架中集成shiro

    官网:https://shiro.apache.org/ 1. 下载在Maven项目中的依赖配置如下: <!-- shiro配置 --> <dependency> <gr ...

  2. 再析在spring框架中解决多数据源的问题

    在前面我写了<如何在spring框架中解决多数据源的问题>,通过设计模式中的Decorator模式在spring框架中解决多数据源的问题,得到了许多网友的关注.在与网友探讨该问题的过程中, ...

  3. Spring框架中 配置c3p0连接池 完成对数据库的访问

    开发准备: 1.导入jar包: ioc基本jar jdbcTemplate基本jar c3p0基本jar 别忘了mysql数据库驱动jar 原始程序代码:不使用配置文件方式(IOC)生成访问数据库对象 ...

  4. Spring框架中ModelAndView、Model、ModelMap区别

    原文地址:http://www.cnblogs.com/google4y/p/3421017.html SPRING框架中ModelAndView.Model.ModelMap区别   注意:如果方法 ...

  5. Spring框架中的定时器 使用和配置

    Spring框架中的定时器 如何使用和配置 转载自:<Spring框架中的定时器 如何使用和配置>https://www.cnblogs.com/longqingyang/p/554543 ...

  6. 【Spring】8、Spring框架中的单例Beans是线程安全的么

    看到这样一个问题:spring框架中的单例Beans是线程安全的么? Spring框架并没有对单例bean进行任何多线程的封装处理.关于单例bean的线程安全和并发问题需要开发者自行去搞定.但实际上, ...

  7. Spring5源码解析-Spring框架中的单例和原型bean

    Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...

  8. Spring框架中IoC(控制反转)的原理(转)

    原文链接:Spring框架中IoC(控制反转)的原理 一.IoC的基础知识以及原理: 1.IoC理论的背景:在采用面向对象方法设计的软件系统中,底层实现都是由N个对象组成的,所有的对象通过彼此的合作, ...

  9. spring框架中的@Import注解

    spring框架中的@Import注解 Spring框架中的@Import注解 在之前的文章中,作者介绍了Spring JavaConfig. 这是除了使用传统的XML文件之外,spring带来的新的 ...

随机推荐

  1. STM32F427VI 电流

  2. Codeforces 1168A Increasing by Modulo

    题目链接:http://codeforces.com/problemset/problem/1168/A 题意:给一个数组,数组中元素范围为0~n,每次你可以选择若干元素进行(ai+1)%m的操作,问 ...

  3. 网页重构应该避免的10大CSS糟糕用法

    对于网页重构来说,CSS禅意花园 是网页布局从 table 表格转到了 html +css 的标志 .这些年来,随着我们的网站越来越复杂:html5,css3,新的技术.新的属性,越来越多的开发者开始 ...

  4. ECMAScript1.1 js书写位置 | 声明变量 | 基本数据类型 | 数据类型转换 | 操作符 | 布尔类型的隐式转换

    js书写位置 由于在写css样式时使用的时双引号,所以我们在写js代码时建议使用单引号(‘’)! 行内式 <input type="button" value="点 ...

  5. 高并发神器 Nginx,到底该怎么学?

    Java技术栈 www.javastack.cn 优秀的Java技术公众号 无论开发还是运维,工作上都会遇到性能优化.高并发的问题,而Nginx是一个万能药,它可以在百万并发连接下实现高吞吐量的 We ...

  6. 使用python和tushare查询股票历史名称变更记录

    接口:namechange 描述:历史名称变更记录 注:tushare库下载和初始化教程,请查阅我之前的文章 输入参数 名称       |       类型       |       必选    ...

  7. linux使用nmon监控、分析系统性能

    linux使用nmon监控.分析系统性能   一.概述 nmon是一种在AIX与各种Linux操作系统上广泛使用的监控与分析工具,相对于其它一些系统资源监控工具来说,nmon所记录的信息是比较全面的, ...

  8. 19-MySQL-Ubuntu-数据表的查询-自关联(八)

    自关联   转自:https://blog.csdn.net/hubingzhong/article/details/81277220

  9. POJ 3525 /// 半平面交 模板

    题目大意: 给定n,接下来n行逆时针给定小岛的n个顶点 输出岛内离海最远的点与海的距离 半平面交模板题 将整个小岛视为由许多半平面围成 那么以相同的比例缩小这些半平面 一直到缩小到一个点时 那个点就是 ...

  10. 解决centos7没有显示ipv4的问题

    很多小伙伴再安装centos7的时候,都是一直默认安装.所以导致后来没有ipv4 那么到底什么原因呢,我最近找到了原因: 就是在这里没有选择: 将这个地方打开之后,就会有了,那么问题就是那个原因.如果 ...