前言
SpringBoot 可以看作是一个配置工具,整合工具,辅助工具,方便了开发工程中的对其他资源的整合,对于许多组件的整合可以达到开箱即用、零配置的效果。SpringBoot 通过引入相应模块对应的 stater 即可整合其他资源,对于web模块的整合亦是如此。下面我们通过源码再次复习一下 springmvc 在处理一个请求的过程中的关键代码,其实要将整个请求的过程说透需要对 web 容器相关的源码足够的熟悉(比如说 Tomcat),本次博文省略这部分的内容,只对 springmvc 的关键步骤做一梳理。
DispatcherServlet源码解析
dispatcher 英 /d??spæt??(r)/ 美 /d??spæt??r/ n. 调度员;[计] 调度程序;[计] 分配器
SpringMVC的核心就是DispatcherServlet,DispatcherServlet实质也是一个HttpServlet。DispatcherSevlet负责将请求分发,所有的请求都有经过它来统一分发。
大致看下SpringMVC请求处理的流程:
用户向服务器发送请求,请求会到DispatcherServlet,DispatcherServlet 对请求URL进行解析,得到请求资源标识符(URI),然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括一个Handler处理器对象、多个HandlerInterceptor拦截器对象),最后以HandlerExecutionChain对象的形式返回。
DispatcherServlet
根据获得的Handler,选择一个合适的HandlerAdapter。提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。
在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
- HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
- 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
- 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
- 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
Handler执行完成后,向DispatcherServlet
返回一个ModelAndView对象;根据返回的ModelAndView,选择一个适合的ViewResolver返回给DispatcherServlet;ViewResolver
结合Model和View,来渲染视图,最后将渲染结果返回给客户端。
DispatcherSevlet中最重要的是doService方法:
//获取请求,设置一些request的参数,然后分发给doDispatch
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name ‘" + getServletName() + "‘" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// 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.
/* 设置web应用上下文**/
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
/* 国际化本地**/
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
/* 样式**/
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
//设置样式资源
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
//请求刷新时保存属性
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
//Flash attributes 在对请求的重定向生效之前被临时存储(通常是在session)中,并且在重定向之后被立即移除
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
//FlashMap 被用来管理 flash attributes 而 FlashMapManager 则被用来存储,获取和管理 FlashMap 实体.
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);
}
}
}
}
doService方法对Request设置了一些全局属性,最终接下来的操作是在doDispatcher:
/**
*将Handler进行分发,handler会被handlerMapping有序的获得
*通过查询servlet安装的HandlerAdapters来获得HandlerAdapters来查找第一个支持handler的类
*所有的HTTP的方法都会被这个方法掌控。取决于HandlerAdapters 或者handlers 他们自己去决定哪些方法是可用
*@param request current HTTP request
*@param response current HTTP response
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
/* 当前HTTP请求**/
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//判断是否有文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// getHandler中遍历HandlerMapping,获取对应的HandlerExecutionChain
// HandlerExecutionChain,包含HandlerIntercrptor和HandlerMethod
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
//获得HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//获得HTTP请求方法
String method = request.getMethod();
boolean isGet = "GET".equals(method);
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;
}
}
//如果有拦截器的话,会执行拦截器的preHandler方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//当view为空时,,根据request设置默认view
applyDefaultViewName(processedRequest, mv);
//执行拦截器的postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
//判断是否是异步请求
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
//删除上传资源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
HandlerInterceptor拦截器
在doDispatcher方法中:
mappedHandler = getHandler(processedRequest);
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name ‘" + getServletName() + "‘");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
遍历HandlerMapping,获取对应的HandlerExecutionChain,HandlerExecutionChain中有3个变量:
private final Object handler; // HandlerMethod
private HandlerInterceptor[] interceptors; //所有的HandlerInterceptor的数组
private List<HandlerInterceptor> interceptorList; //所有的HandlerInterceptor的链表
在执行Controller的方法调用之前先执行:
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
HandlerExecutionChain#applyPreHandle
即调用HandlerInterceptor# preHandler
方法。在Controller的方法调用之后:
mappedHandler.applyPostHandle(processedRequest, response, mv);
HandlerExecutionChain#applyPostHandle
即调用HandlerInterceptor# postHandle
方法。最后
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
方法会调用:
mappedHandler.triggerAfterCompletion(request, response, null);
调用HandlerInterceptor#afterCompletion
方法。
详细用法参考 https://blog.csdn.net/zero__007/article/details/80028720
HandlerMapping和HandlerExecutionChain
** * Interface to be implemented by objects that define a mapping between * requests and handler objects. * * <p>This class can be implemented by application developers, although this is not * necessary, as {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping} * and {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping} * are included in the framework. The former is the default if no * HandlerMapping bean is registered in the application context. * * <p>HandlerMapping implementations can support mapped interceptors but do not * have to. A handler will always be wrapped in a {@link HandlerExecutionChain} * instance, optionally accompanied by some {@link HandlerInterceptor} instances. * The DispatcherServlet will first call each HandlerInterceptor‘s * {@code preHandle} method in the given order, finally invoking the handler * itself if all {@code preHandle} methods have returned {@code true}. * * <p>The ability to parameterize this mapping is a powerful and unusual * capability of this MVC framework. For example, it is possible to write * a custom mapping based on session state, cookie state or many other * variables. No other MVC framework seems to be equally flexible. * * <p>Note: Implementations can implement the {@link org.springframework.core.Ordered} * interface to be able to specify a sorting order and thus a priority for getting * applied by DispatcherServlet. Non-Ordered instances get treated as lowest priority. * * @author Rod Johnson * @author Juergen Hoeller * @see org.springframework.core.Ordered * @see org.springframework.web.servlet.handler.AbstractHandlerMapping * @see org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping */ public interface HandlerMapping { package org.springframework.web.servlet; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; /** * Handler execution chain, consisting of handler object and any handler interceptors. * Returned by HandlerMapping‘s {@link HandlerMapping#getHandler} method. * * @author Juergen Hoeller * @since 20.06.2003 * @see HandlerInterceptor */ public class HandlerExecutionChain {
请求和及请求对应的映射关系查看
请求的url有对应的cotroller的映射
请求的url没有对应的隐射---->静态资源中去找
原文地址:https://www.cnblogs.com/tombky/p/12625290.html