SpringMVC源码剖析(二):哀求执行流程
SpringMVC源码系列文章SpringMVC源码剖析(一):web容器启动流程
SpringMVC源码剖析(二):哀求执行流程
前言
前文中我们介绍了SpringMVC容器的启动,包括前端控制器DispatcherServlet对象的创建,过滤器添加到Tomcat容器的过滤器集合中,将全部拦截器、跨域设置、消息转换器等设置统一添加到各自集合中,剖析@RequestMapping注解生成哀求路径和Controller方法的映射map。本章来研究下哀求的执行过程。
说到哀求过程,那么得先说下入口在哪里?入口肯定是统一分发哀求给处置惩罚程序的DispatcherServlet,DispatcherServlet归根结底也是Servlet。Tomcat通过哀求Mapping映射和Servelt对应关系找到Servelt,调用Servelt之前会执行过滤器链,全部过滤器放行才会走到Servelt真正的执行逻辑。
[*]依照常见的post哀求为例
// 接受User对象并返回
@PostMapping("/test")
@ResponseBody
public User test(@RequestBody User user) {
user.setName("李四");
System.out.println(user);
return user;
}
[*]方法栈调用链
https://i-blog.csdnimg.cn/direct/304096b704944651bab7fb24bcbd2021.png
[*]HttpServelt#service分水岭doPost方法,只要找到DispatcherServelt重写的doPost方法就是入口了
https://i-blog.csdnimg.cn/direct/f5a7e1a7d2484e779ff663c0ce20a2f3.png
本文就不讲过滤器的调用了,因为从DispatcherServelt开始,过滤器链已经执行完成,之前文章Tomcat源码剖析(八):一个哀求的执行流程(附Tomcat整体总结)有介绍过。
DispatcherServlet入口
DispatcherServlet的类图如下:
https://i-blog.csdnimg.cn/direct/67ab878324364126b7884f4c65868596.png
从doPost到doDispatch方法
[*]doPost方法是由DispatcherServelt的父类FrameworkServlet实现的
[*]岂论post还是get哀求都是调用同一个方法processRequest(request, response)
[*]对于方法参数request和respons都是Tomcat容器创建的,以前文章Tomcat源码剖析(七):底层怎样获取哀求url、哀求头、json数据?有详细介绍
https://i-blog.csdnimg.cn/direct/a6c5a3ee3a064ff0b9fe60eff239f4d1.png
[*]主要方法doService(request, response)
// FrameworkServlet类方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
...
try {
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
...
}
}
[*]主要方法doDispatch(request, response)
// DispatcherServlet类方法
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ... 设置一堆Attribute属性
try {
doDispatch(request, response);
}
finally {
...
}
}
核心方法doDispatch
[*]这个方法包含了SpringMVC的整个执行流程
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;
try {
// 判断是否上传请求,以后有机会单独将
processedRequest = checkMultipart(request);
// 如果是上传请求,这个参数置为true,最后会去清理资源
multipartRequestParsed = (processedRequest != request);
// 获取HandlerExcutionChain (内部包括Handler)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 请求url找不到404就会走到这里
noHandlerFound(processedRequest, response);
return;
}
// 获取适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// get请求缓存相关,以后有机会单独将
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;
}
}
// 调用拦截器的前置方法preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行handler方法
// 需要跳转页面这里才会返回ModelAndView对象,否则@ResponseBody返回对象这里返回null
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 调用拦截器的后置方法postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
//从4.3开始,我们也在处理处理程序方法抛出的错误,
//使它们可用于@ExceptionHandler方法和其他场景。
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 调用拦截器请求处理完成后的回调triggerAfterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
// 调用拦截器请求处理完成后的回调triggerAfterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// 异步处理的回调
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 如果是上传请求,清理相关资源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
一、获取HandlerExcutionChain(包括Handler)
遍历全部的HandlerMapping,只要getHandler方法能获取到HandlerExecutionChain立即返回。
// DispatcherServlet类方法
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
如下这三个HandlerMapping是web容器启动时候加载的,上篇文章SpringMVC源码剖析(一):web容器启动流程有详细介绍。三个轮番调用getHandler方法,而HandlerMapping也有次序的,RequestMappingHanderMapping排序为0优先级最高,而它也是处置惩罚@RequestMapping注解的映射关系的映射器。
https://i-blog.csdnimg.cn/direct/80eef563fcbd40d78dc19711234ff198.png
调用抽象类的方法,那么上面看到的三个HandlerMapping应该都会调用此方法,而这里肯定有一些核心的不同的方法实现在不同的HandlerMapping详细实现类中,典型的模板方法计划模式。
// AbstractHandlerMapping类方法
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获取Handler
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// handler为bean的名称
// 这种Controller应该是实现Controler、HttpRequestHandler接口的方式
// 以前的老实现方式,暂不研究
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
...
// 获取执行链(包括Handler和拦截器)
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// ...打印日志
// 添加跨域设置(本身也是拦截器)到拦截器链中第一个位置
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;
}
1、获取Handler
[*]主要内容就是调用父类AbstractHandlerMethodMapping的雷同方法
// RequestMappingInfoHandlerMapping类方法
@Override
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
try {
// 核心方法调用父类的getHandlerInternal方法
return super.getHandlerInternal(request);
}
finally {
ProducesRequestCondition.clearMediaTypesAttribute(request);
}
}
[*]通过request获取查找路径
[*]通过查找路径获取HandlerMethod
// AbstractHandlerMethodMapping类方法
@Override
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 通过request获取查找路径
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
// 通过查找路径获取HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
1.1、通过request获取查找路径
[*]截取哀求uri,如图/springmvc/test,/springmvc为项目路径,/test为我们需要的查找路径
https://i-blog.csdnimg.cn/direct/5b9e68a3f1e54aeebbfd91ba58fe50f0.png
1.2、通过查找路径获取HandlerMethod
这个方法的核心内容就是从之前讲的SpringMVC源码剖析(一):web容器启动流程注册的两个map获取数据。
https://i-blog.csdnimg.cn/direct/4605bb00107c42e0897fc71497456418.png
// AbstractHandlerMethodMapping类方法
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 通过查找路径获取RequestMappingInfo
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
// 通过RequestMappingInfo获取HandlerMethod
addMatchingMappings(directPathMatches, matches, request);
}
...
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
//...匹配多个,抛错异常
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
handleMatch(bestMatch.mapping, lookupPath, request);
// 获取HandlerMethod并返回
return bestMatch.getHandlerMethod();
}
else {
return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
}
https://i-blog.csdnimg.cn/direct/c408fa733770427480fd76b0436232a2.png
2、获取执行链(包括Handler、拦截器)
我们自定义的拦截器统一用MappedInterceptor这个拦截器包装了一层,为了统一调用matcher方法,匹配此拦截器哀求是否拦截本次哀求,如果是则会添加到拦截器链中。
// AbstractHandlerMapping类方法
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 创建HandlerExecutionChain对象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 遍历所有的拦截器,这拦截器是web容器启动时候解析加载的的
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 我们自定义的拦截器统一用MappedInterceptor这个拦截器包装了一层
// 为了统一的匹配方法,下面调用maches
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// matcher匹配当前请求路径是否符合拦截器的拦截请求
if (mappedInterceptor.matches(request)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
// 执行器链对象,主要就是两个属性handler:Handler对象,interceptorList:拦截器集合
public class HandlerExecutionChain {
private final Object handler;
private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
// 构造方法
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[]) null);
}
...
}
[*]拦截器链终极的结果
https://i-blog.csdnimg.cn/direct/bd3282c1381e4e12a6c6ff068c300ea6.png
二、获取适配器
看下HandlerAdapter接口
public interface HandlerAdapter {
/**
* 因为有多个HandlerMapping和HandlerAdapter
* 对于HandlerAdapter是否支持对应的HandlerMapping,通过此方法判断
*/
boolean supports(Object handler);
/**
* 具体调用Hangder的方法
*/
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
因为不同的Hander(@RequestMapping、实现Controller接口、实现HttpRequestHandler接口)对应的HandlerAdapter(适配器)不一样,通过HandlerAdapter的supports方法判断当前HandlerAdapter是否支持此次哀求的Hander。
// DispatcherServlet类方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
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");
}
[*]这个是抽象类实现的supports方法,全部HandlerAdapter判断是否支持都会走这里
[*]其主要作用就是supportsInternal方法,在不同的HandlerAdapter实现类中重写
[*]RequestMappingHandlerAdapter重写的supportsInternal返回true,表示其支持
// AbstractHandlerMethodAdapter类方法
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
// RequestMappingHandlerAdapter类方法
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
由上面HandlerAdapter接口可以猜到,RequestMappingHandlerAdapter适配器就是我们需要的,之后会通过handle方法去执行Hangder方法即调用Controller#Method。
三、执行Handler(
页:
[1]