前一小节我们分析了SpringMVC容器的启动,DispatcherServlet的初始化,HandleMapping,HandleAdaptor,主题,视图解析器等组件的准备工作,现在可以开始接收请求了。我们一般不提倡覆盖Servlet的service方法,除非有特殊的需要。springMVC就覆盖了这个方法,我们来看下SpringMVC都做了什么操作
protected void org.springframework.web.servlet.FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//如果请求方法是patch的时候走processRequest,其他情况还是走的servlet
//的默认实现
if (HttpMethod.PATCH.matches(request.getMethod())) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
但是你点开doGet,doPost等方法,基本上都是调用的processRequest方法,那就很奇怪了,为什么要像上面那样写代码,那是因为默认的servlet实现没有patch请求方法,所以这里做了特殊处理。
好了,我们直接看到processRequest方法
protected final void org.springframework.web.servlet.FrameworkServlet.processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//从当前线程中获取LocaleContext,也就是locale国际化使用的,LocaleContextHolder内部持有两个ThreadLocal,其中
//有一个是继承父线程值的InheritableLocale
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//使用locale解析器从request中解析出locale,然后封装成LocaleContext
LocaleContext localeContext = buildLocaleContext(request);
//又是从ThreadLocal中获取资源,RequestAttributes可以存储属性-》值键值对,也可以获取对应key的值
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//构建ServletRequestAttributes,持有request,可以存属性值到tomcat的request中,也可以存在tomcat的session中
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
//创建异步处理器,用于支持servlet3提供的异步请求
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//添加回调拦截器,用于在异步调用处理逻辑的时候绑定localeContext, requestAttributes
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//初始化上下文,其实就是将 localeContext, requestAttributes绑定到当前请求线程中
initContextHolders(request, localeContext, requestAttributes);
try {
//处理服务
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
//恢复旧的值
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
//调用请求销毁回调,更新session信息,并标记请求结束
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
//触发请求处理事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
doService
protected void org.springframework.web.servlet.DispatcherServlet.doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
。。。。。。
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
//保存快照,以便修改好可以恢复
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
//DispatcherServlet.class.getName() + ".CONTEXT" -> WebApplicationContext
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
//DispatcherServlet.class.getName() + ".LOCALE_RESOLVER" -> this.localeResolver
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
//DispatcherServlet.class.getName() + ".THEME_RESOLVER" -> this.themeResolver
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
//DispatcherServlet.class.getName() + ".THEME_SOURCE" -> getThemeSource()
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
//获取上次保存的FlashMap和更新FlashMap,去除过期的FlashMap
//(*1*)
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
//DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP" -》 inputFlashMap
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
//DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP" -》 new FlashMap()
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
//DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER" -》 this.flashMapManager
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
//分发请求
doDispatch(request, response);
}
finally {
//异步请求是否仍在进行中或者已经结束或者还未开始
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
//恢复快照属性值
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
//(*1*)
public final FlashMap org.springframework.web.servlet.support.AbstractFlashMapManager.retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {
//从session中获取属性为SessionFlashMapManager.class.getName() + ".FLASH_MAPS"的值
//这是所有的FlashMap,FlashMap一个继承了HashMap的类
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
if (CollectionUtils.isEmpty(allFlashMaps)) {
return null;
}
if (logger.isDebugEnabled()) {
logger.debug("Retrieved FlashMap(s): " + allFlashMaps);
}
//获取过期的FlashMap
List<FlashMap> mapsToRemove = getExpiredFlashMaps(allFlashMaps);
//获取匹配的FlashMap,匹配规则:请求路径一样,FlashMap中期望的参数名是实际request的请求参数的子集
//FlashMap中期望的参数值也是实际request的请求参数值的子集
//对所有符合要求的进行排序,参数长的优先
FlashMap match = getMatchingFlashMap(allFlashMaps, request);
if (match != null) {
//加入到移除集合中,因为这个匹配到FlashMap会在此次请求中使用
mapsToRemove.add(match);
}
if (!mapsToRemove.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Removing FlashMap(s): " + mapsToRemove);
}
//获取互斥锁,一般是从session获取,属性值为WebUtils.class.getName() + ".MUTEX",如果没有设置
//那么直接返回session作为互斥锁
Object mutex = getFlashMapsMutex(request);
if (mutex != null) {
//同步,一般对于同一个session,也就是同一个用户其实很少出现这种并发的情况
//当然这也是有可能的,比如异步请求,可能请求的延时,就有可能发生竞争
synchronized (mutex) {
//从session中重新获取,可能已经发生了更新
allFlashMaps = retrieveFlashMaps(request);
if (allFlashMaps != null) {
//移除
allFlashMaps.removeAll(mapsToRemove);
//更新到request中
updateFlashMaps(allFlashMaps, request, response);
}
}
}
else {
//移除
allFlashMaps.removeAll(mapsToRemove);
//更新到request
updateFlashMaps(allFlashMaps, request, response);
}
}
return match;
}
doDispatch
protected void org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//获取异步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查这个请求是否是上传请求,如果是,那么包装这个Request
//spring提供了两种方式,如果是servlet3以上的,将使用servlet的part进行文件流的封装
//如果不是将使用Apache提供的文件处理组件处理
processedRequest = checkMultipart(request);
//如果对象发生了变化,那么说明当前请求被解析成了multipartRequest
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//获取mappedHandler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
//打印No mapping found,可以配置为抛出错误,默认是直接返回404
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//寻找能够处理当前handler的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
//判断是否过期,如果没有过去,设置response为304
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
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;
}
// Actually invoke the handler.
//通过适配器处理handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//异步请求是否已经结束
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//如果没有设置视图(可能是字符串类型的视图名,也有可能是具体的View对象)
applyDefaultViewName(processedRequest, mv);
//应用拦截器器的后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//处理分发结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//调用全局异常处理,如果有必要还会渲染错误信息视图,最后调用拦截器的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
//调用全局异常处理,如果有必要还会渲染错误信息视图,最后调用拦截器的afterCompletion方法
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
//如果异步处理还在处理
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
//从拦截器中寻找AsyncHandlerInterceptor,并调用其afterConcurrentHandlingStarted方法
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
//如果是上传请求,清理文件(清理内存,或者文件比较大的话还会存在临时文件)
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
从请求转发的代码中,我们可以看到,spring处理请求总体上分为这几部:
- 通过HandleMapping寻找handler
- 如果没有找到,打印日志,然后就是报错或者报404(可在web.xml中配置)
- 寻找能够处理handler的adapter
- 是否是get或者head请求,对比缓存时间,如果没有过期直接返回304
- 调用拦截器前置处理
- adapter处理handler
- 处理默认视图名,比如返回void,默认的命名转换器会将request的uri进行转换,去除前后的/,去除扩展名
- 调用拦截器后置处理
- 如果有错误并且不是ModelAndViewDefiningException,调用全局异常处理器
- 解析视图,渲染视图
- 调用拦截器的complete处理
- 如果是异步处理,还会调用同步后置处理
- 如果是上传请求,会清理上传资源
下面我们大致看下获取handler的逻辑
protected HandlerExecutionChain org.springframework.web.servlet.DispatcherServlet.getHandler(HttpServletRequest request) throws Exception {
//循环所有的HandlerMapping,如果有一个找打handler并停止继续向下执行
for (HandlerMapping hm : this.handlerMappings) {
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
获取HandlerExecutionChain,HandlerExecutionChain是一个驱动类,用于驱动链条执行的驱动器
public class HandlerExecutionChain {
//日志
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
//handler对象
private final Object handler;
//拦截器数组
private HandlerInterceptor[] interceptors;
//拦截器集合
private List<HandlerInterceptor> interceptorList;
//当前执行到的下标位置,如果某个拦截器发生拦截(下标还是指向的还是上一个拦截器),那么triggerAfterCompletion方法将从这个下标开始
//向前执行
private int interceptorIndex = -1;
。。。。。。
}
HandlerExecutionChain.applyPreHandle
boolean org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
//如果被拦截立马执行当前拦截器的triggerAfterCompletion方法,
//从前一个拦截器的下标开始从后往前执行
triggerAfterCompletion(request, response, null);
return false;
}
//记录执行到下标
this.interceptorIndex = i;
}
}
return true;
}
HandlerExecutionChain.applyPostHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//从后往前执行
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
HandlerExecutionChain.triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//从之前记录的拦截器位置,向前执行
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
接下来将进入HandlerMapping的学习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2021-05-18 12、Netty的内存池之PoolArena
2017-05-18 springboot-thymeleaf
2017-05-18 springboot-redis
2017-05-18 springBoot综合开发
2017-05-18 spring boot 入门篇
2017-05-18 Integrating Thymeleaf with Spring
2017-05-18 thymeleaf常用属性