SpringMVC源码剖析(二):哀求执行流程

打印 上一主题 下一主题

主题 702|帖子 702|积分 2106

SpringMVC源码系列文章
SpringMVC源码剖析(一):web容器启动流程
SpringMVC源码剖析(二):哀求执行流程


  
前言

  前文中我们介绍了SpringMVC容器的启动,包括前端控制器DispatcherServlet对象的创建,过滤器添加到Tomcat容器的过滤器集合中,将全部拦截器、跨域设置、消息转换器等设置统一添加到各自集合中,剖析@RequestMapping注解生成哀求路径和Controller方法的映射map。本章来研究下哀求的执行过程。
  说到哀求过程,那么得先说下入口在哪里?入口肯定是统一分发哀求给处置惩罚程序的DispatcherServlet,DispatcherServlet归根结底也是Servlet。Tomcat通过哀求Mapping映射和Servelt对应关系找到Servelt,调用Servelt之前会执行过滤器链,全部过滤器放行才会走到Servelt真正的执行逻辑。


  • 依照常见的post哀求为例
  1. // 接受User对象并返回
  2. @PostMapping("/test")
  3. @ResponseBody
  4. public User test(@RequestBody User user) {
  5.     user.setName("李四");
  6.     System.out.println(user);
  7.     return user;
  8. }
复制代码


  • 方法栈调用链



  • HttpServelt#service分水岭doPost方法,只要找到DispatcherServelt重写的doPost方法就是入口了

  本文就不讲过滤器的调用了,因为从DispatcherServelt开始,过滤器链已经执行完成,之前文章Tomcat源码剖析(八):一个哀求的执行流程(附Tomcat整体总结)有介绍过。
DispatcherServlet入口

DispatcherServlet的类图如下:

   从doPost到doDispatch方法
  

  • doPost方法是由DispatcherServelt的父类FrameworkServlet实现的
  • 岂论post还是get哀求都是调用同一个方法processRequest(request, response)
  • 对于方法参数request和respons都是Tomcat容器创建的,以前文章Tomcat源码剖析(七):底层怎样获取哀求url、哀求头、json数据?有详细介绍



  • 主要方法doService(request, response)
  1. // FrameworkServlet类方法
  2. protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
  3.                 throws ServletException, IOException {
  4.         long startTime = System.currentTimeMillis();
  5.         Throwable failureCause = null;
  6.         ...
  7.         try {
  8.                 doService(request, response);
  9.         }
  10.         catch (ServletException | IOException ex) {
  11.                 failureCause = ex;
  12.                 throw ex;
  13.         }
  14.         catch (Throwable ex) {
  15.                 failureCause = ex;
  16.                 throw new NestedServletException("Request processing failed", ex);
  17.         }
  18.         finally {
  19.                 ...
  20.         }
  21. }
复制代码


  • 主要方法doDispatch(request, response)
  1. // DispatcherServlet类方法
  2. @Override
  3. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  4.         // ... 设置一堆Attribute属性
  5.         try {
  6.                 doDispatch(request, response);
  7.         }
  8.         finally {
  9.                 ...
  10.         }
  11. }
复制代码
  核心方法doDispatch
  

  • 这个方法包含了SpringMVC的整个执行流程
  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2.         HttpServletRequest processedRequest = request;
  3.         HandlerExecutionChain mappedHandler = null;
  4.         boolean multipartRequestParsed = false;
  5.        
  6.         // 异步请求相关,以后单独篇章讲
  7.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  8.         try {
  9.                 ModelAndView mv = null;
  10.                 Exception dispatchException = null;
  11.                 try {
  12.                         // 判断是否上传请求,以后有机会单独将
  13.                         processedRequest = checkMultipart(request);
  14.                         // 如果是上传请求,这个参数置为true,最后会去清理资源
  15.                         multipartRequestParsed = (processedRequest != request);
  16.                         // 获取HandlerExcutionChain (内部包括Handler)
  17.                         mappedHandler = getHandler(processedRequest);
  18.                         if (mappedHandler == null) {
  19.                                 // 请求url找不到404就会走到这里
  20.                                 noHandlerFound(processedRequest, response);
  21.                                 return;
  22.                         }
  23.                         // 获取适配器
  24.                         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  25.                         // get请求缓存相关,以后有机会单独将
  26.                         String method = request.getMethod();
  27.                         boolean isGet = HttpMethod.GET.matches(method);
  28.                         if (isGet || HttpMethod.HEAD.matches(method)) {
  29.                                 long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  30.                                 if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
  31.                                         return;
  32.                                 }
  33.                         }
  34.                        
  35.                         // 调用拦截器的前置方法preHandle
  36.                         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  37.                                 return;
  38.                         }
  39.                         // 执行handler方法
  40.                         // 需要跳转页面这里才会返回ModelAndView对象,否则@ResponseBody返回对象这里返回null
  41.                         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  42.                         if (asyncManager.isConcurrentHandlingStarted()) {
  43.                                 return;
  44.                         }
  45.                         applyDefaultViewName(processedRequest, mv);
  46.                         // 调用拦截器的后置方法postHandle
  47.                         mappedHandler.applyPostHandle(processedRequest, response, mv);
  48.                 }
  49.                 catch (Exception ex) {
  50.                         dispatchException = ex;
  51.                 }
  52.                 catch (Throwable err) {
  53.                         //从4.3开始,我们也在处理处理程序方法抛出的错误,
  54.                         //使它们可用于@ExceptionHandler方法和其他场景。
  55.                         dispatchException = new NestedServletException("Handler dispatch failed", err);
  56.                 }
  57.                 // 处理结果
  58.                 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  59.         }
  60.         catch (Exception ex) {
  61.                 // 调用拦截器请求处理完成后的回调triggerAfterCompletion
  62.                 triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  63.         }
  64.         catch (Throwable err) {
  65.                 // 调用拦截器请求处理完成后的回调triggerAfterCompletion
  66.                 triggerAfterCompletion(processedRequest, response, mappedHandler,
  67.                                 new NestedServletException("Handler processing failed", err));
  68.         }
  69.         finally {
  70.                 if (asyncManager.isConcurrentHandlingStarted()) {
  71.                         // 异步处理的回调
  72.                         if (mappedHandler != null) {
  73.                                 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
  74.                         }
  75.                 }
  76.                 else {
  77.                         // 如果是上传请求,清理相关资源
  78.                         if (multipartRequestParsed) {
  79.                                 cleanupMultipart(processedRequest);
  80.                         }
  81.                 }
  82.         }
  83. }
复制代码
一、获取HandlerExcutionChain(包括Handler)

  遍历全部的HandlerMapping,只要getHandler方法能获取到HandlerExecutionChain立即返回。
  1. // DispatcherServlet类方法
  2. @Nullable
  3. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  4.         if (this.handlerMappings != null) {
  5.                 for (HandlerMapping mapping : this.handlerMappings) {
  6.                         HandlerExecutionChain handler = mapping.getHandler(request);
  7.                         if (handler != null) {
  8.                                 return handler;
  9.                         }
  10.                 }
  11.         }
  12.         return null;
  13. }
复制代码
  如下这三个HandlerMapping是web容器启动时候加载的,上篇文章SpringMVC源码剖析(一):web容器启动流程有详细介绍。三个轮番调用getHandler方法,而HandlerMapping也有次序的,RequestMappingHanderMapping排序为0优先级最高,而它也是处置惩罚@RequestMapping注解的映射关系的映射器。

  调用抽象类的方法,那么上面看到的三个HandlerMapping应该都会调用此方法,而这里肯定有一些核心的不同的方法实现在不同的HandlerMapping详细实现类中,典型的模板方法计划模式。
  1. // AbstractHandlerMapping类方法
  2. @Override
  3. @Nullable
  4. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  5.         // 获取Handler
  6.         Object handler = getHandlerInternal(request);
  7.         if (handler == null) {
  8.                 handler = getDefaultHandler();
  9.         }
  10.         if (handler == null) {
  11.                 return null;
  12.         }
  13.         // handler为bean的名称
  14.         // 这种Controller应该是实现Controler、HttpRequestHandler接口的方式
  15.         // 以前的老实现方式,暂不研究
  16.         if (handler instanceof String) {
  17.                 String handlerName = (String) handler;
  18.                 handler = obtainApplicationContext().getBean(handlerName);
  19.         }
  20.        
  21.         ...
  22.        
  23.         // 获取执行链(包括Handler和拦截器)
  24.         HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
  25.         // ...打印日志
  26.        
  27.         // 添加跨域设置(本身也是拦截器)到拦截器链中第一个位置
  28.         if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
  29.                 CorsConfiguration config = getCorsConfiguration(handler, request);
  30.                 if (getCorsConfigurationSource() != null) {
  31.                         CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
  32.                         config = (globalConfig != null ? globalConfig.combine(config) : config);
  33.                 }
  34.                 if (config != null) {
  35.                         config.validateAllowCredentials();
  36.                 }
  37.                 executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
  38.         }
  39.         return executionChain;
  40. }
复制代码
1、获取Handler



  • 主要内容就是调用父类AbstractHandlerMethodMapping的雷同方法
  1. // RequestMappingInfoHandlerMapping类方法
  2. @Override
  3. @Nullable
  4. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
  5.         request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
  6.         try {
  7.                 // 核心方法调用父类的getHandlerInternal方法
  8.                 return super.getHandlerInternal(request);
  9.         }
  10.         finally {
  11.                 ProducesRequestCondition.clearMediaTypesAttribute(request);
  12.         }
  13. }
复制代码


  • 通过request获取查找路径
  • 通过查找路径获取HandlerMethod
  1. // AbstractHandlerMethodMapping类方法
  2. @Override
  3. @Nullable
  4. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
  5.         // 通过request获取查找路径
  6.         String lookupPath = initLookupPath(request);
  7.         this.mappingRegistry.acquireReadLock();
  8.         try {
  9.                 // 通过查找路径获取HandlerMethod
  10.                 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
  11.                 return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
  12.         }
  13.         finally {
  14.                 this.mappingRegistry.releaseReadLock();
  15.         }
  16. }
复制代码
1.1、通过request获取查找路径



  • 截取哀求uri,如图/springmvc/test,/springmvc为项目路径,/test为我们需要的查找路径

1.2、通过查找路径获取HandlerMethod

  这个方法的核心内容就是从之前讲的SpringMVC源码剖析(一):web容器启动流程注册的两个map获取数据。

  1. // AbstractHandlerMethodMapping类方法
  2. @Nullable
  3. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
  4.         List<Match> matches = new ArrayList<>();
  5.         // 通过查找路径获取RequestMappingInfo
  6.         List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
  7.         if (directPathMatches != null) {
  8.                 // 通过RequestMappingInfo获取HandlerMethod
  9.                 addMatchingMappings(directPathMatches, matches, request);
  10.         }
  11.         ...
  12.         if (!matches.isEmpty()) {
  13.                 Match bestMatch = matches.get(0);
  14.                 if (matches.size() > 1) {
  15.                         //...匹配多个,抛错异常
  16.                 }
  17.                 request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
  18.                 handleMatch(bestMatch.mapping, lookupPath, request);
  19.                 // 获取HandlerMethod并返回
  20.                 return bestMatch.getHandlerMethod();
  21.         }
  22.         else {
  23.                 return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
  24.         }
  25. }
复制代码

2、获取执行链(包括Handler、拦截器)

  我们自定义的拦截器统一用MappedInterceptor这个拦截器包装了一层,为了统一调用matcher方法,匹配此拦截器哀求是否拦截本次哀求,如果是则会添加到拦截器链中。
  1. // AbstractHandlerMapping类方法
  2. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
  3.         // 创建HandlerExecutionChain对象
  4.         HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
  5.                         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
  6.        
  7.         // 遍历所有的拦截器,这拦截器是web容器启动时候解析加载的的
  8.         for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
  9.                 // 我们自定义的拦截器统一用MappedInterceptor这个拦截器包装了一层
  10.                 // 为了统一的匹配方法,下面调用maches
  11.                 if (interceptor instanceof MappedInterceptor) {
  12.                         MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
  13.                         // matcher匹配当前请求路径是否符合拦截器的拦截请求
  14.                         if (mappedInterceptor.matches(request)) {
  15.                                 chain.addInterceptor(mappedInterceptor.getInterceptor());
  16.                         }
  17.                 }
  18.                 else {
  19.                         chain.addInterceptor(interceptor);
  20.                 }
  21.         }
  22.         return chain;
  23. }
  24. // 执行器链对象,主要就是两个属性handler:Handler对象,interceptorList:拦截器集合
  25. public class HandlerExecutionChain {
  26.         private final Object handler;
  27.         private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
  28.         // 构造方法
  29.         public HandlerExecutionChain(Object handler) {
  30.                 this(handler, (HandlerInterceptor[]) null);
  31.         }
  32.         ...
  33. }
复制代码


  • 拦截器链终极的结果

二、获取适配器

   看下HandlerAdapter接口
  1. public interface HandlerAdapter {
  2.         /**
  3.          * 因为有多个HandlerMapping和HandlerAdapter
  4.          * 对于HandlerAdapter是否支持对应的HandlerMapping,通过此方法判断
  5.          */
  6.         boolean supports(Object handler);
  7.         /**
  8.          * 具体调用Hangder的方法
  9.          */
  10.         @Nullable
  11.         ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
  12. }
复制代码
  因为不同的Hander(@RequestMapping、实现Controller接口、实现HttpRequestHandler接口)对应的HandlerAdapter(适配器)不一样,通过HandlerAdapter的supports方法判断当前HandlerAdapter是否支持此次哀求的Hander。
  1. // DispatcherServlet类方法
  2. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  3.         if (this.handlerAdapters != null) {
  4.                 for (HandlerAdapter adapter : this.handlerAdapters) {
  5.                         if (adapter.supports(handler)) {
  6.                                 return adapter;
  7.                         }
  8.                 }
  9.         }
  10.         throw new ServletException("No adapter for handler [" + handler +
  11.                         "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
  12. }
复制代码


  • 这个是抽象类实现的supports方法,全部HandlerAdapter判断是否支持都会走这里
  • 其主要作用就是supportsInternal方法,在不同的HandlerAdapter实现类中重写

    • RequestMappingHandlerAdapter重写的supportsInternal返回true,表示其支持

  1. // AbstractHandlerMethodAdapter类方法
  2. @Override
  3. public final boolean supports(Object handler) {
  4.         return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
  5. }
  6. // RequestMappingHandlerAdapter类方法
  7. @Override
  8. protected boolean supportsInternal(HandlerMethod handlerMethod) {
  9.         return true;
  10. }
复制代码
  由上面HandlerAdapter接口可以猜到,RequestMappingHandlerAdapter适配器就是我们需要的,之后会通过handle方法去执行Hangder方法即调用Controller#Method。
三、执行Handler(

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

北冰洋以北

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表