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带来的新的 ...
随机推荐
- Java-Class-C:java.util.HashMap
ylbtech-Java-Class-C:java.util.HashMap 1.返回顶部 1.1. import java.util.HashMap; import java.util.Map; 1 ...
- 如何优雅的使用Objects.requireNonNull(T obj, String message)定制你的NPE异常
IDEA中习惯跟踪源码实现逻辑,多次碰到Objects.requireNonNull(T obj)这个方法,改方法主要用于提早判断对象是否为空,以便更早的抛出NPE 平时小组开发中强调程序健壮性,不允 ...
- USACO 2008 January Silver Telephone Lines /// 二分最短路 邻接表dijkstra oj22924
题目大意: 一共有N (1 ≤ N ≤ 1,000)个电线杆,有P P (1 ≤ P ≤ 10,000)对电线杆是可以连接的, 用几条线连接在一起的电线杆之间都可相互通信,现在想要使得电线杆1和电线杆 ...
- POJ1149_PIGS(网络流/EK)
PIGS Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 15721 Accepted: 7021 Description ...
- 使用Echarts的步骤
Echarts官网地址:https://echarts.baidu.com/index.html 步骤如下: 1.获取Echarts (1)可以在Echarts官网去下载,选择需要的版本下载,根据开发 ...
- cookie与token对比(转)
1.cookie(储存在用户本地终端上的数据( 为了辨别用户身份.进行 session 跟踪)) HTTP协议本身是无状态的,所以需要一个标志来对用户身份进行验证 用户登录成功后,会在服务器存一个se ...
- H5点击拨打电话,发短信
phone(){ window.location.href = 'tel:123123'// 拨打电话 window.location.href = 'sms:123123'// 发短信 }
- LR调试脚本的时候报错Error -27796:(已解决)
LR调试bbs脚本的时候报错: 1.Error -27796: Failed to connect to server "192.168.211.128:80": [10060] ...
- .net下MVC中使用Tuple分页查询数据
主要是在DAL层写查询分页的代码. 例如DAL层上代码: public Tuple<List<WxBindDto>, int> GetMbersInfo(int start, ...
- 校园商铺-4店铺注册功能模块-3thumbnailator图片处理和封装Util
1. 初步使用thumbnailator 1.1 下载依赖 <!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator - ...