业务处理流程
- 请求匹配:通过
HandlerMapping
查找合适的处理器。 - 拦截器前置处理:执行所有的
HandlerInterceptor
的preHandle
方法。 - 执行控制器方法:调用相应的控制器方法处理请求。
- 数据处理:
- 如果是视图返回,进行视图解析并渲染。
- 如果是数据返回,使用
HttpMessageConverter
转换成合适的格式(如 JSON)。
- 拦截器后处理:执行所有
HandlerInterceptor
的postHandle
方法。 - 视图渲染:将模型数据和视图渲染成最终的响应内容。
- 后置清理:执行所有
HandlerInterceptor
的afterCompletion
方法。 - 异常处理:如果有异常发生,进行异常处理。
doDispatch 源码
@SuppressWarnings("deprecation")
protected void 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;
// 请求处理(这里后面详细分析,1、2、3)
try { ... }
catch (Exception ex) {
// 如果发生异常,赋值给 dispatchException 变量
dispatchException = ex;
}
catch (Throwable err) {
// 如果发生错误,也赋值给 dispatchException
dispatchException = new ServletException("Handler dispatch failed: " + err, err);
}
// 结果处理(后面详细分析,4、5、6)
// 1,如果 dispatchException 不为空,说明请求处理发生了异常,使用异常解析器处理异常(如果异常解析器也发生异常呢?所以外层还有一层 try catch)
// 2,如果 dispatchException 为空,说明请求处理正常,该返回视图或 json 都是这里做的
// 3,也会执行拦截器的 afterCompletion 方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 如果异常解析器也发生异常,也要执行拦截器的 afterCompletion 方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
// 如果异常解析器也发生错误,也要执行拦截器的 afterCompletion 方法
triggerAfterCompletion(processedRequest, response, mappedHandler,
new ServletException("Handler processing failed: " + err, err));
}
finally {
// 如果是异步请求的后续处理
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 如果是文件请求的后续处理
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
通过上面源码分析可以知道
- 不管 handler 执行异常还是成功,拦截器的 afterCompletion 一定会执行(顺序是倒序执行)
- 内层 try catch 是处理 handler 执行异常,外层 try catch 是当异常解析器处理也发生异常的处理
寻找和执行 handler 源码
也就是内层的 try catch 不分,源码如下
// 1,检查是否是文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 2,寻找处理器 Handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 3,寻找 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// get head 请求用于获取资源,静态资源比如 css、图片等,动态资源比如 jsp、freemarket、servlet 等
// 当资源没有被修改并且缓存未失效就返回缓存
// 前后分离后这个缓存就没啥意义了
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 执行拦截器,如果不放行,请求处理结束,不会执行 handler
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 真正执行 handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
检查是否是文件上传请求
// org.springframework.web.servlet.DispatcherServlet#checkMultipart
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
// 文件解析器不为空并且 ContentType 为 multipart/form-data 打头
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
// request 是否是 MultipartHttpServletRequest(如果不是会返回 null)
if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
if (DispatcherType.REQUEST.equals(request.getDispatcherType())) {
logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
}
} else if (hasMultipartException(request)) {
logger.debug("Multipart resolution previously failed for current request - " +
"skipping re-resolution for undisturbed error rendering");
} else {
try {
// 使用文件解析器解析请求
return this.multipartResolver.resolveMultipart(request);
} catch (MultipartException ex) {
if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
logger.debug("Multipart resolution failed for error dispatch", ex);
// Keep processing error dispatch with regular request handle below
} else {
throw ex;
}
}
}
}
// 文件解析器肯定不会空,内置好了的。如果 ContentType 为=不是以 multipart/form-data 打头,就返回原 request
return request;
}
// org.springframework.web.multipart.support.StandardServletMultipartResolver#resolveMultipart
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
// 成员变量 resolveLazily 默认值是 false
return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}
// org.springframework.web.multipart.support.StandardMultipartHttpServletRequest#StandardMultipartHttpServletRequest(jakarta.servlet.http.HttpServletRequest, boolean)
public StandardMultipartHttpServletRequest(HttpServletRequest request, boolean lazyParsing) throws MultipartException {
// 调用到好几辈的父类构造,目的就是赋值,把 request 赋值给成员变量
super(request);
// StandardMultipartHttpServletRequest 的成员变量 lazyParsing 默认就是 false
if (!lazyParsing) {
// 这里真正解析
this.parseRequest(request);
}
}
// org.springframework.web.multipart.support.StandardMultipartHttpServletRequest#parseRequest
private void parseRequest(HttpServletRequest request) {
try {
// Servlet 3.0 新引入的 API,当 Content-Type 为 multipart/form-data 时方便从 HTTP 请求中获取表单字段和文件
Collection<Part> parts = request.getParts();
this.multipartParameterNames = new LinkedHashSet(parts.size());
MultiValueMap<String, MultipartFile> files = new LinkedMultiValueMap(parts.size());
// Part 是代表请求中的每一部分的对象。每个 Part 对象可以包含上传的文件或普通的表单字段
for (Part part : parts) {
String headerValue = part.getHeader("Content-Disposition");
ContentDisposition disposition = ContentDisposition.parse(headerValue);
String filename = disposition.getFilename();
if (filename != null) {
files.add(part.getName(), new StandardMultipartFile(part, filename));
} else {
this.multipartParameterNames.add(part.getName());
}
}
// 就不贴源码了,源码就是下面这行注释,这个方法就是把 parts 解析后的 map 赋值给 multipartFiles 变量
// this.multipartFiles = new LinkedMultiValueMap(Collections.unmodifiableMap(multipartFiles));
this.setMultipartFiles(files);
} catch (Throwable ex) {
this.handleParseFailure(ex);
}
}
寻找 Handler
// org.springframework.web.servlet.DispatcherServlet#getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// MVC 启动时会维护好 handlerMappings
// 默认有 RequestMappingHandlerMapping(处理@RequestMapping注解实现的 handler)、RouterFunctionmapping 等
if (this.handlerMappings != null) {
// 遍历所有的 处理器映射器 (处理器映射器维护了 url 和 handler,根据 url 就能找到 handler)
for (HandlerMapping mapping : this.handlerMappings) {
// 得到的是 处理器执行链(处理器+拦截器)
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
// org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获取 handler(RequestMappingHandlerMapping 的 mappingRegistry 的 registry 中维护了所有 url 和 handler)
// 这个方法内部还是有点逻辑,打个断点看下看下处理器映射器的各个属性就会比较清晰了
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// 获取到的 handler 是否是字符串,如果是字符串就找对应的 bean 作为 handler
if (handler instanceof String handlerName) {
handler = obtainApplicationContext().getBean(handlerName);
}
// 请求缓存(把请求url写到request属性中,后续再处理就不用计算url了,直接可以从request中拿到)
if (!ServletRequestPathUtils.hasCachedPath(request)) {
initLookupPath(request);
}
// 这个方法比较简单,就是取出所有拦截器加上 handler 组合成 HandlerExecutionChain(这里就会用到上面写到request的url)
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
logger.debug("Mapped to " + executionChain.getHandler());
}
// 跨域处理
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = getCorsConfiguration(handler, request);
if (getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
config = (globalConfig != null ? globalConfig.combine(config) : config);
}
if (config != null) {
config.validateAllowCredentials();
}
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
// 返回处理器执行链
return executionChain;
}
寻找 HandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// 通处理器映射器一致,处理器适配器也是mvc启动就维护好了,也有好几种类型,RequestMappingHandlerAdapter 处理 @RequestMapping 注解实现的 handler
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// 每个适配器通过 supports 决定支持处理哪种 handler
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
// 实现 jakarta.servlet.Servlet 接口的 handler 对应的适配器
public boolean supports(Object handler) {
return (handler instanceof Servlet);
}
// 实现 org.springframework.web.servlet.mvc.Controller 接口的 handler 对应的适配器
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
// @RequestMapping 实现的 handler 对应的适配器(会被封装为 HandlerMethod 对象)
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod handlerMethod && supportsInternal(handlerMethod));
}
标签:null,return,请求,mappedHandler,request,handler,DispatcherServlet,源码,processedReque
From: https://www.cnblogs.com/cyrushuang/p/18650135