Spring 框架中Http请求处理流程
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请求处理流程的更多相关文章
- 细说shiro之五:在spring框架中集成shiro
官网:https://shiro.apache.org/ 1. 下载在Maven项目中的依赖配置如下: <!-- shiro配置 --> <dependency> <gr ...
- 再析在spring框架中解决多数据源的问题
在前面我写了<如何在spring框架中解决多数据源的问题>,通过设计模式中的Decorator模式在spring框架中解决多数据源的问题,得到了许多网友的关注.在与网友探讨该问题的过程中, ...
- Spring框架中 配置c3p0连接池 完成对数据库的访问
开发准备: 1.导入jar包: ioc基本jar jdbcTemplate基本jar c3p0基本jar 别忘了mysql数据库驱动jar 原始程序代码:不使用配置文件方式(IOC)生成访问数据库对象 ...
- Spring框架中ModelAndView、Model、ModelMap区别
原文地址:http://www.cnblogs.com/google4y/p/3421017.html SPRING框架中ModelAndView.Model.ModelMap区别 注意:如果方法 ...
- Spring框架中的定时器 使用和配置
Spring框架中的定时器 如何使用和配置 转载自:<Spring框架中的定时器 如何使用和配置>https://www.cnblogs.com/longqingyang/p/554543 ...
- 【Spring】8、Spring框架中的单例Beans是线程安全的么
看到这样一个问题:spring框架中的单例Beans是线程安全的么? Spring框架并没有对单例bean进行任何多线程的封装处理.关于单例bean的线程安全和并发问题需要开发者自行去搞定.但实际上, ...
- Spring5源码解析-Spring框架中的单例和原型bean
Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...
- Spring框架中IoC(控制反转)的原理(转)
原文链接:Spring框架中IoC(控制反转)的原理 一.IoC的基础知识以及原理: 1.IoC理论的背景:在采用面向对象方法设计的软件系统中,底层实现都是由N个对象组成的,所有的对象通过彼此的合作, ...
- spring框架中的@Import注解
spring框架中的@Import注解 Spring框架中的@Import注解 在之前的文章中,作者介绍了Spring JavaConfig. 这是除了使用传统的XML文件之外,spring带来的新的 ...
随机推荐
- 20140404 OpencvGPU模块 参考文献交叉引用:引用->题注 加入3.1,3.2,3.2编号
1.参考文献交叉引用:引用->题注 2.加入3.1,3.2,3.2编号:开始->段落 3.OpencvGPU模块,编译opencv.sln时记得在库目录中添加D:\opencv\build ...
- 9款很棒的网页绘制图表JavaScript框架脚本
推荐9款很棒的可在网页中绘制图表的JavaScript脚本,这些有趣的JS脚本可以帮助你快速方便的绘制图表(线.面.饼.条…),其中包括jQuery.MooTools.Prototype和一些其它的J ...
- 2018-8-10-VisualStduio-打断点调试和不打断点调试有什么区别
title author date CreateTime categories VisualStduio 打断点调试和不打断点调试有什么区别 lindexi 2018-08-10 19:16:52 + ...
- C#中,用户控件UserControl里面用Panl加载UserControl,并实现利用委托互相传值
用户控件主窗体结构:左侧树形菜单,右侧Panl: 根据点击的菜单节点,panl里面选择性加载某一个子窗体用户控件,并传值给子窗体: 反之,在子窗体进行相应的操作之后,传值给主窗体,触发主窗体的刷新. ...
- MySQL数据库之DQL(数据查询语言)
1.MySQL之DQL查询AS CONCAT LIKE的使用 (1)select 列名1,列名2,...... from 表名 [where 条件] 查询所有字段用*,不带where条件的话,就会把表 ...
- Android开发 Button的开发记录
Button置顶层效果取消 android:stateListAnimator="@null" 在代码里执行点击 mButton.performClick(); //点击 mBut ...
- SpringDataJPA在Entity中常用的注解浅析
首先我们常用的注解包括(@Entity.@Table.@Id.@IdClass.@GeneratedValue.@Basic.@Transient.@Column.@Temporal.@Enumera ...
- [转]SpringMVC框架入门配置 IDEA下搭建Maven项目
初衷:本人初学SpringMVC的时候遇到各种稀奇古怪的问题,网上各种技术论坛上的帖子又参差不齐,难以一步到位达到配置好的效果,这里我将我配置的总结写到这里供大家初学SpringMVC的同僚们共同学习 ...
- CUDA 关于 BLOCK数目与Thread数目设置
GPU的计算核心是以一定数量的Streaming Processor(SP)组成的处理器阵列,NV称之为Texture Processing Clusters(TPC),每个TPC中又包含一定数量的S ...
- csp-s模拟测试85
csp-s模拟测试85 $T1$全场秒切没有什么区分度,$T2$全场成功转化题意但是我并不会打,$T3$暴力都没打很遗憾. 100 00:21:49 02:56:35 02:56:49 135 02: ...