SpringMVC请求流程原理

原文转自:https://blog.csdn.net/nuomizhende45/article/details/85715148

请求流程原理:

  •     第一步:发起请求到前端控制器(DispatcherServlet)
  •     第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找)
  •     第三步:处理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略
  •     第四步:前端控制器调用处理器适配器去执行Handler
  •     第五步:处理器适配器HandlerAdapter将会根据适配的结果去执行Handler
  •     第六步:Handler执行完成给适配器返回ModelAndView
  •     第七步:处理器适配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一个底层对象,包括 Model和view)
  •     第八步:前端控制器请求视图解析器去进行视图解析 (根据逻辑视图名解析成真正的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可
  •     第九步:视图解析器向前端控制器返回View
  •     第十步:前端控制器进行视图渲染 (视图渲染将模型数据(在ModelAndView对象中)填充到request域)
  •     第十一步:前端控制器向用户响应结果
     

请求流程图:

 

 一、发起请求前端控制器DispatcherServlet,分析DispatcherServlet类的结构

这里我们发现了这个DispatcherServlet通过继承FrameWorkServlet、HttpServletBean从而间接的继承了HttpServlet,所以说这个DispatcherServlet也是一个Servlet,它也能通过Servlet的API来响应请求,从而成为一个前端控制器。Web容器会调用Servlet的doGet()以及doPost()等方法,这里FrameworkServlet重写了HttpServlet的这两个方法,里面都调用了processRequest这个方法

 继续跟进,经过了一些简单的处理后发现最终还是调用了doService方法

继续跟进这个doService方法,发现它是一个等待子类实现的抽象方法,DispatcherServlet是它的子类并且实现了该方法,所以最终请求时通过FrameworkServlet的简单处理之后调用了DispatcherServletdoService方法

 至此我们已经清楚了为什么DispatcherServlet为前端控制器了

 二、分析前端控制器DispatcherServlet的启动和初始化的过程

通过前面分析已经知道了DispatcherServlet这个前端控制器是一个Servlet了,所以生命周期和普通的Servlet是差不多的,在一个Servlet初始化的时候都会调用该Servlet的init()方法。下面这个是DispatcherSerlvet父类HttpServletBean中的init方法。

 我们发现这里会调用initServletBean()方法进行具体的初始化,而该类这个方法的具体实现这是其子类FrameworkServlet。主要逻辑就是初始化上下文。

  1.     protected final void initServletBean() throws ServletException {
  2.         this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " \'" + this.getServletName() + "\'");
  3.         if(this.logger.isInfoEnabled()) {
  4.             this.logger.info("Initializing Servlet \'" + this.getServletName() + "\'");
  5.         }
  6.  
  7.         long startTime = System.currentTimeMillis();
  8.  
  9.         try {
  10.             /**
  11.             这里初始化上下文
  12.             **/
  13.             this.webApplicationContext = this.initWebApplicationContext();
  14.             this.initFrameworkServlet();
  15.         } catch (RuntimeException | ServletException var4) {
  16.             this.logger.error("Context initialization failed", var4);
  17.             throw var4;
  18.         }
  19.  
  20.         if(this.logger.isDebugEnabled()) {
  21.             String value = this.enableLoggingRequestDetails?"shown which may lead to unsafe logging of potentially sensitive data":"masked to prevent unsafe logging of potentially sensitive data";
  22.             this.logger.debug("enableLoggingRequestDetails=\'" + this.enableLoggingRequestDetails + "\': request parameters and headers will be " + value);
  23.         }
  24.  
  25.         if(this.logger.isInfoEnabled()) {
  26.             this.logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
  27.         }
  28.  
  29.     }

 继续跟进这个onRefresh方法,发现是一个模板方法,其具体实现子类则是DispatcherServlet。

 跳转到DispatcherServlet中查看该方法,发现里面又调用了initStrategies这个方法

 这时我们就大致了解了,这个DispatcherServlet初始化的过程了,首先DispatcherServlet持有着一个以自己的Servlet名字命名的Ioc容器,也就是我们看到的WebApplicationContext对象,这个Ioc容器建立起来后,与Web容器相关的各种配置加载也都完成了。并且这个初始化的入口就是由最初的HttpServletBean的init方法触发的,因为这个HttpServletBean是HttpServlet的子类,接下来HttpServletBean的子类FrameworkServlet对Ioc容器进行了初始化操作,并且利用onRefresh方法回调了DispatcherServlet中的initStrategies方法,在这个方法里启动了整个SpringMVC框架,我们继续往下面跟进看看。

 


    

  1. //该属性默认为true
  2.     private boolean detectAllHandlerMappings = true;
  3.  
  4. private void initHandlerMappings(ApplicationContext context) {
  5.         this.handlerMappings = null;
  6.         //这里面的逻辑是从导入所有的HandlerMappingBean,这些Bean有可能存在与双亲容器中,也可能在DispathcerServlet持有的容器的,这里detectAllHandlerMappings默认为true,默认从所有容器中导入
  7.         if(this.detectAllHandlerMappings) {
  8.             Map hm = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
  9.             if(!hm.isEmpty()) {
  10.                 this.handlerMappings = new ArrayList(hm.values());
  11.                 AnnotationAwareOrderComparator.sort(this.handlerMappings);
  12.             }
  13.         } else {
  14.             //否则通过直接通过名字从当前的IOC容器中通过getBean方法获取handlerMapping
  15.             try {
  16.                 HandlerMapping hm1 = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
  17.                 this.handlerMappings = Collections.singletonList(hm1);
  18.             } catch (NoSuchBeanDefinitionException var3) {
  19.                 ;
  20.             }
  21.         }
  22.         //如果还是没有找到hadlerMapping就需要设定默认的handlerMappings了
  23.         if(this.handlerMappings == null) {
  24.             this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
  25.             if(this.logger.isTraceEnabled()) {
  26.                 this.logger.trace("No HandlerMappings declared for servlet \'" + this.getServletName() + "\': using default strategies from DispatcherServlet.properties");
  27.             }
  28.         }
  29.    }

下面是用debugger看看它究竟获取了那些handlerMapping,如下:7个handlerMapping

 除了这个初始化handlerMapping的initHandlerMapping方法,当然还初始化了很多东西,如支持国际化的LocalResolver以及视图生成的ViewResolver等的初始化过程,其余的有兴趣自己跟着看一下,这里就不细跟了。到这里我们就知道了整个DispatcherServlet的初始化的大体流程。接下来继续了解以下MVC是如何处理我们HTTP请求并映射到对应的handler处理的,也就是对应着最上面的二、三、四、五步骤。

 三、HTTP请求是如何与对应Handler的对应method映射的

从上面的分析已经知道了当初始化完成的时候context中所有的handlerMapping都被加载了,并且它们都存放在hadlerMappings这么一个List中并且被排序了。我们看看HandlerMapping的设计及类的结构关系如下: 

 

 这里可以看到顶层的父接口就是HandlerMapping,进入这个类发现这个顶层接口定义了一些常量以及一个getHandler方法,并且通过该方法会返回HandlerExecutionChain这么一个对象。

 跟进这个HandlerExecutionChain这个类看看,这个类中有这么Interceptor链和一个handler这个两个关键的成员。说白了这个handler就是HTTP请求对应的那个Controller,并且这个Interceptor链也就是我们配置的各种拦截器,多个拦截器组成了拦截器链,通过拦截器链对我们handler进行一系列的增强。当然这个HandlerExecutionChain类还提供了一些维护这个拦截器链的API

  1. public class HandlerExecutionChain {
  2.     private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
  3.     private final Object handler;
  4.     @Nullable
  5.     private HandlerInterceptor[] interceptors;
  6.     @Nullable
  7.     private List<HandlerInterceptor> interceptorList;
  8.     private int interceptorIndex;
  9.  
  10.     public HandlerExecutionChain(Object handler) {
  11.         this(handler, (HandlerInterceptor[])null);
  12.     }
  13.  
  14.     public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
  15.         this.interceptorIndex = -1;
  16.         if(handler instanceof HandlerExecutionChain) {
  17.             HandlerExecutionChain originalChain = (HandlerExecutionChain)handler;
  18.             this.handler = originalChain.getHandler();
  19.             this.interceptorList = new ArrayList();
  20.             CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
  21.             CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
  22.         } else {
  23.             this.handler = handler;
  24.             this.interceptors = interceptors;
  25.         }
  26.  
  27.     }
  28.  
  29.     public Object getHandler() {
  30.         return this.handler;
  31.     }
  32.  
  33.     public void addInterceptor(HandlerInterceptor interceptor) {
  34.         this.initInterceptorList().add(interceptor);
  35.     }
  36.  
  37.     public void addInterceptors(HandlerInterceptor... interceptors) {
  38.         if(!ObjectUtils.isEmpty(interceptors)) {
  39.             CollectionUtils.mergeArrayIntoCollection(interceptors, this.initInterceptorList());
  40.         }
  41.  
  42.     }
  43.  
  44.     private List<HandlerInterceptor> initInterceptorList() {
  45.         if(this.interceptorList == null) {
  46.             this.interceptorList = new ArrayList();
  47.             if(this.interceptors != null) {
  48.                 CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
  49.             }
  50.         }
  51.  
  52.         this.interceptors = null;
  53.         return this.interceptorList;
  54.     }
  55.  
  56.     @Nullable
  57.     public HandlerInterceptor[] getInterceptors() {
  58.         if(this.interceptors == null && this.interceptorList != null) {
  59.             this.interceptors = (HandlerInterceptor[])this.interceptorList.toArray(new HandlerInterceptor[0]);
  60.         }
  61.  
  62.         return this.interceptors;
  63.     }
  64.  
  65.     boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
  66.         HandlerInterceptor[] interceptors = this.getInterceptors();
  67.         if(!ObjectUtils.isEmpty(interceptors)) {
  68.             for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
  69.                 HandlerInterceptor interceptor = interceptors[i];
  70.                 if(!interceptor.preHandle(request, response, this.handler)) {
  71.                     this.triggerAfterCompletion(request, response, (Exception)null);
  72.                     return false;
  73.                 }
  74.             }
  75.         }
  76.  
  77.         return true;
  78.     }
  79.  
  80.     void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
  81.         HandlerInterceptor[] interceptors = this.getInterceptors();
  82.         if(!ObjectUtils.isEmpty(interceptors)) {
  83.             for(int i = interceptors.length - 1; i >= 0; --i) {
  84.                 HandlerInterceptor interceptor = interceptors[i];
  85.                 interceptor.postHandle(request, response, this.handler, mv);
  86.             }
  87.         }
  88.  
  89.     }
  90.  
  91.     void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
  92.         HandlerInterceptor[] interceptors = this.getInterceptors();
  93.         if(!ObjectUtils.isEmpty(interceptors)) {
  94.             for(int i = this.interceptorIndex; i >= 0; --i) {
  95.                 HandlerInterceptor interceptor = interceptors[i];
  96.  
  97.                 try {
  98.                     interceptor.afterCompletion(request, response, this.handler, ex);
  99.                 } catch (Throwable var8) {
  100.                     logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
  101.                 }
  102.             }
  103.         }
  104.  
  105.     }
  106.  
  107.     void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
  108.         HandlerInterceptor[] interceptors = this.getInterceptors();
  109.         if(!ObjectUtils.isEmpty(interceptors)) {
  110.             for(int i = interceptors.length - 1; i >= 0; --i) {
  111.                 if(interceptors[i] instanceof AsyncHandlerInterceptor) {
  112.                     try {
  113.                         AsyncHandlerInterceptor ex = (AsyncHandlerInterceptor)interceptors[i];
  114.                         ex.afterConcurrentHandlingStarted(request, response, this.handler);
  115.                     } catch (Throwable var6) {
  116.                         logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", var6);
  117.                     }
  118.                 }
  119.             }
  120.         }
  121.  
  122.     }
  123.  
  124.     public String toString() {
  125.         Object handler = this.getHandler();
  126.         StringBuilder sb = new StringBuilder();
  127.         sb.append("HandlerExecutionChain with [").append(handler).append("] and ");
  128.         if(this.interceptorList != null) {
  129.             sb.append(this.interceptorList.size());
  130.         } else if(this.interceptors != null) {
  131.             sb.append(this.interceptors.length);
  132.         } else {
  133.             sb.append(0);
  134.         }
  135.         return sb.append(" interceptors").toString();
  136.     }
  137. }

 大致了解了Handler与HandlerExecutionChain后,就可以开始具体分析SpringMVC对HTTP请求处理的原理了,这里以我们最常用的RequestMappingHandlerMapping为例子,首先看看它的类继承体系

 这里主要关注的是RequestMappingInfoHandlerMapping、AbstractHandlerMethodMapping。从这张Diagrams图可以发现,这个AbstractHandlerMethodMapping实现了InitializingBean接口并且实现了afterPropertiesSet方法。

 并且整个初始化工作由AbstractHandlerMethodMapping的initHandlerMethods方法主导的。为什么这么说呢,我们都知道SpringBean在创建bean的过程是先经过了bean的实例化、bean的属性填充、bean的初始化等步骤。 

 

 那么在SpringBean初始化的时候会调用invokeInitMethods方法它会去判断该bean是否为InitializingBean的实例,是的话就去调用它的afterPropertiesSet方法

  到这里终于清楚了为什么说整个初始化的工作是由AbstractHandlerMethodMapping的initHandlerMethods主导了,原因就是在这个类中Spring回调方法afterPropertiesSet里面又调用了initHandlerMethods方法。

  接下来主要分析以下这个initHandlerMethods方法究竟干了什么,大体逻辑就是先获取应用中所有Object的bean的名字,然后遍历它循环获取这个beanName对应的beanType,判断这个bean是不是一个handler

  1.    protected void initHandlerMethods() {
  2.         if(this.logger.isDebugEnabled()) {
  3.             this.logger.debug("Looking for request mappings in application context: " + this.getApplicationContext());
  4.         }
  5.         //这里是获取应用中所有Object的bean的名字
  6.         String[] beanNames = this.detectHandlerMethodsInAncestorContexts?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.obtainApplicationContext(), Object.class):this.obtainApplicationContext().getBeanNamesForType(Object.class);
  7.         String[] var2 = beanNames;
  8.         int var3 = beanNames.length;
  9.         //遍历这个含有应用中所有beanName的字符串数组,并得到这个beanName对应的bean的类型
  10.         for(int var4 = 0; var4 < var3; ++var4) {
  11.             String beanName = var2[var4];
  12.             if(!beanName.startsWith("scopedTarget.")) {
  13.                 Class beanType = null;
  14.  
  15.                 try {
  16.                     //根据这个beanName对应的beanType的类型
  17.                     beanType = this.obtainApplicationContext().getType(beanName);
  18.                 } catch (Throwable var8) {
  19.                     if(this.logger.isDebugEnabled()) {
  20.                         this.logger.debug("Could not resolve target class for bean with name \'" + beanName + "\'", var8);
  21.                     }
  22.                 }
  23.                 //判断这个根据这个bean的类型判断是不是一个handler
  24.                 if(beanType != null && this.isHandler(beanType)) {
  25.                     this.detectHandlerMethods(beanName);
  26.                 }
  27.             }
  28.         }
  29.  
  30.         this.handlerMethodsInitialized(this.getHandlerMethods());
  31.     }

 并且从代码中我们可以知道判断一个Bean是不是一个Handler的逻辑就是判断这个Bean是否含有Controller注解RequestMapping注解

 若这个Bean是一个Handler那么就进入detectHandlerMethods方法处理,去检测发现对应的HandlerMethod。继续跟进这个方法看看。这个方法的大体逻辑是获取这个handler中所有由requestMappinng的方法,然后循环去注册该方法与对应requestMapping信息到一个名为registry的一个HashMap中去,具体逻辑继续往下看。

  1.     protected void detectHandlerMethods(Object handler) {
  2.         Class handlerType = handler instanceof String?this.obtainApplicationContext().getType((String)handler):handler.getClass();
  3.         if(handlerType != null) {
  4.             Class userType = ClassUtils.getUserClass(handlerType);
  5.             //获取这个handler中有requestMapping的方法
  6.             //这个methods的Map结构为key是一个Method对象,value是一个RequestMappingInfo对象
  7.             //这个版本的代码是5.0.4的,这里用到了lambda表达,这里可以理解成匿名类
  8.             Map methods = MethodIntrospector.selectMethods(userType, (method) -> {
  9.                 try {
  10.                     return this.getMappingForMethod(method, userType);
  11.                 } catch (Throwable var4) {
  12.                     throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, var4);
  13.                 }
  14.             });
  15.             if(this.logger.isDebugEnabled()) {
  16.                 this.logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
  17.             }
  18.             //循环去注册Method与RequestMappingInfo的关系
  19.             methods.forEach((method, mapping) -> {
  20.                 Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
  21.                 this.registerHandlerMethod(handler, invocableMethod, mapping);
  22.             });
  23.         }
  24.  }

 

首先看看这个selectMethods方法到底做了什么,从字面意思理解是按照规则来选取给定的类里面中方法。具体逻辑细化可以分为两步.

第一步:若这个targetType不是一个代理类,就获得它本身的类以及它的接口放入handlerTypes这么一个Set中去。

第二步:遍历这个handlerTypes,找到用户自己定义的方法并过滤出有requestMapping的方法,并将之塞入一个methodMap中

  1.    public static <T> Map<Method, T> selectMethods(Class<?> targetType, MethodIntrospector.MetadataLookup<T> metadataLookup) {
  2.         LinkedHashMap methodMap = new LinkedHashMap();
  3.         LinkedHashSet handlerTypes = new LinkedHashSet();
  4.         Class specificHandlerType = null;
  5.         //若这个targetType不是一个代理类,就获得它本身的类以及它的接口
  6.         if(!Proxy.isProxyClass(targetType)) {
  7.             specificHandlerType = ClassUtils.getUserClass(targetType);
  8.             handlerTypes.add(specificHandlerType);
  9.         }
  10.  
  11.         handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
  12.         Iterator var5 = handlerTypes.iterator();
  13.         //遍历
  14.         while(var5.hasNext()) {
  15.             Class currentHandlerType = (Class)var5.next();
  16.             Class targetClass = specificHandlerType != null?specificHandlerType:currentHandlerType;
  17.             //找到用户自己定义的方法并过滤出有requestMapping的方法,并将之塞入一个methodMap中
  18.             ReflectionUtils.doWithMethods(currentHandlerType, (method) -> {
  19.                 Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
  20.                 Object result = metadataLookup.inspect(specificMethod);
  21.                 if(result != null) {
  22.                     Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
  23.                     if(bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
  24.                         methodMap.put(specificMethod, result);
  25.                     }
  26.                 }
  27.  
  28.             }, ReflectionUtils.USER_DECLARED_METHODS);
  29.         }
  30.  
  31.         return methodMap;
  32.     }

 

下面继续跟进这个ReflectUtilsl.doWithMethods方法看看究竟是何方神圣。

先来了解以下它的方法入参:第一个是Class、第二个是MethodCallback、第三个是MethodFilter。第一个不用解释了,第二个从字面意思就能看出来就是一个方法回调,第三个也好理解是一个方法过滤器;具体后面再说。

 

大致清楚它的参数后再来看看这个方法的内部逻辑,可以看到逻辑也比较简单:

1、首先获取这个Class中所有定义的方法并且将之存入一个methods的Method数组中

2、遍历这个methods数组中的method如果这个mf方法拦截器为空或者这个method与方法拦截器mf的匹配规则对应,就回调mc.doWith方法。 

3、后面我们还发现对这个类的父类和接口都有一个递归调用

  1.     public static void doWithMethods(Class<?> clazz, ReflectionUtils.MethodCallback mc, @Nullable ReflectionUtils.MethodFilter mf) {
  2.         //首先获取这个Class中所有定义的方法并且将之存入一个methods的Method数组中
  3.         Method[] methods = getDeclaredMethods(clazz);
  4.         Method[] var4 = methods;
  5.         int var5 = methods.length;
  6.  
  7.         int var6;
  8.         for(var6 = 0; var6 < var5; ++var6) {
  9.             Method superIfc = var4[var6];
  10.         //遍历这个methods数组中的method
  11.         //如果这个mf方法拦截器为空或者这个method与方法拦截器mf的匹配规则对应,就回调mc.doWith方法。
  12.             if(mf == null || mf.matches(superIfc)) {
  13.                 try {
  14.                     //调用回调方法
  15.                     mc.doWith(superIfc);
  16.                 } catch (IllegalAccessException var9) {
  17.                     throw new IllegalStateException("Not allowed to access method \'" + superIfc.getName() + "\': " + var9);
  18.                 }
  19.             }
  20.         }
  21.  
  22.         if(clazz.getSuperclass() != null) {
  23.             doWithMethods(clazz.getSuperclass(), mc, mf);
  24.         } else if(clazz.isInterface()) {
  25.             Class[] var10 = clazz.getInterfaces();
  26.             var5 = var10.length;
  27.  
  28.             for(var6 = 0; var6 < var5; ++var6) {
  29.                 Class var11 = var10[var6];
  30.                 doWithMethods(var11, mc, mf);
  31.             }
  32.         }
  33.     }

 

了解这个方法的逻辑之后,再回过头来看看selectMethod方法中的ReflectUtilsl.doWithMethods就很清楚了。

这个mc.doWith就对应这一段逻辑,可以看到这段逻辑里面有一个metadataLookup.inspect方法,这个方法的逻辑就是selectMethods传入的第二个入参的。就是调用了RequestMappingHandlerMapping的getMappingForMethod方法

 

 

 而这个getMappingForMethod干的事情就是找到这个方法上的RequestMapping,如果这个方法上的requestMapping信息不为空的话就去照这个handler类上面的requestMapping信息然后将之合并。

然后这个mf方法拦截器就是这个RelectionUtils.USER_DECLARED_METHODS;顾名思义就是用户自己定义的方法,而非继承与Object类的方法什么的

 

 所以这下detectHandlerMethods里面上半部分在干什么就已经知道了:无非就是获取这个handler类里面用户自定义的方法中有requestMapping注解信息的方法,并将该方法作为key,requestMapping注解信息作为value存入一个名为methods的Map中去 

 这里不得不提到这个RequestMappingInfo这个类,这个类就是封装了requestMapping注解信息的这么一个类,有兴趣的可以自己去看看它的内部定义,这里就不详解了。

 接下来这个方法中就只剩下了这么一小段逻辑了,看名字就知道应该是遍历这个methods注册handlerMethod到某个地方去。

 继续跟进这个方法看看,里面并没有做什么而是调用了另外一个方法,继续跟进。

 

 终于找到了最终的实现,首先加了一把锁,考虑的两个requestMapping并发注册的问题;然后根据这个handler与method获取了一个HandlerMethod对象,这个对象包含了handler与method的信息;接着确保同一个requestMapping唯一映射一个method,因为不可能说一个url路径 /aaa/bbb 又对应methodA 又对应methodB是不允许的’;最终注册这个requestMappingInfo与对应handlerMethod的关系。(这里有意思的事情是发现有这么一个log的info语句 “Mapped xxx onto xxxx” 是不是在SpringBoot项目或者SpringMVC项目启动的时候控制台上见过,没错就是这里的)

  1.        public void register(T mapping, Object handler, Method method) {
  2.             this.readWriteLock.writeLock().lock();
  3.  
  4.             try {
  5.     //根据这个handler与method获取了一个HandlerMethod对象,这个对象包含了handler与method的信息
  6.                 HandlerMethod handlerMethod = AbstractHandlerMethodMapping.this.createHandlerMethod(handler, method);
  7.     //确保同一个requestMapping唯一映射一个method
  8.     //因为不可能说一个url路径 /aaa/bbb 又对应methodA 又对应methodB是不允许的
  9.                 this.assertUniqueMethodMapping(handlerMethod, mapping);
  10.                 if(AbstractHandlerMethodMapping.this.logger.isInfoEnabled()) {
  11.                     AbstractHandlerMethodMapping.this.logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
  12.                 }
  13.                 //后面都差不多是注册requestMapping与HandlerMethodInfo的关系
  14.                 this.mappingLookup.put(mapping, handlerMethod);
  15.                 List directUrls = this.getDirectUrls(mapping);
  16.                 Iterator name = directUrls.iterator();
  17.  
  18.                 while(name.hasNext()) {
  19.                     String corsConfig = (String)name.next();
  20.                     this.urlLookup.add(corsConfig, mapping);
  21.                 }
  22.  
  23.                 String name1 = null;
  24.                 if(AbstractHandlerMethodMapping.this.getNamingStrategy() != null) {
  25.                     name1 = AbstractHandlerMethodMapping.this.getNamingStrategy().getName(handlerMethod, mapping);
  26.                     this.addMappingName(name1, handlerMethod);
  27.                 }
  28.  
  29.                 CorsConfiguration corsConfig1 = AbstractHandlerMethodMapping.this.initCorsConfiguration(handler, method, mapping);
  30.                 if(corsConfig1 != null) {
  31.                     this.corsLookup.put(handlerMethod, corsConfig1);
  32.                 }
  33.  
  34.                 this.registry.put(mapping, new AbstractHandlerMethodMapping.MappingRegistration(mapping, handlerMethod, directUrls, name1));
  35.             } finally {
  36.                 this.readWriteLock.writeLock().unlock();
  37.             }
  38.         }

 至此这个 detectHandlerMethods 方法的逻辑全都清楚了,前面先找寻出又requestMapping信息的method,接着就是将这个handler里面的RequestMappingInfo与一个HandlerMethod建立映射关系。

 所以建立映射关系这一步已经全都清楚了,最后贴一个启动的控制台语句,果然对应的上非常 的有成就感啊。

 

小结:

说白了我们常用的@RequestMapping映射处理的初始化是由SpringIOC的这么一个回调接口InitializingBean来主导的,由于AbstractHandlerMethodMapping这个父类实现了InitializingBean,所以SpringIOC容器会回调父类的这么一个afterPropertiesSet方法,最后间接的调用了initHandlerMethods这个方法。在initHandlerMethods这个方法里面就是得到容器中所有的beanName,遍历这个beanName得到它的beanType,再看这个beanType是不是由@Controller或者@RequestMapping这个注解判断它是否是一个Handler,若是就去获取这个handler中所有含有requestMapping的方法,并放入一个key为Method并且value为RequestMappingInfo这么Map中去,接着遍历这个map注册ReuquestMappingInfo与HandlerMethod这么一个映射关系。这个HandlerMethod方法其实就是包含着handler与method的这么一个类。

 四、SpingMVC处理Http请求原理

 当一个http请求过来了首先经过的是DispatcherServlet这么一个前端控制器并调用了这个前端控制器的doService方法。这个方法最终我们发现它调用了doDispatcher这么一个方法。这就是SpringMVC处理http请求的入口了。

  1.    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2.         if(this.logger.isDebugEnabled()) {
  3.             String attributesSnapshot = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()?" resumed":"";
  4.             this.logger.debug("DispatcherServlet with name \'" + this.getServletName() + "\'" + attributesSnapshot + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
  5.         }
  6.  
  7.         HashMap attributesSnapshot1 = null;
  8.         if(WebUtils.isIncludeRequest(request)) {
  9.             attributesSnapshot1 = new HashMap();
  10.             Enumeration inputFlashMap = request.getAttributeNames();
  11.  
  12.             label112:
  13.             while(true) {
  14.                 String attrName;
  15.                 do {
  16.                     if(!inputFlashMap.hasMoreElements()) {
  17.                         break label112;
  18.                     }
  19.  
  20.                     attrName = (String)inputFlashMap.nextElement();
  21.                 } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
  22.  
  23.                 attributesSnapshot1.put(attrName, request.getAttribute(attrName));
  24.             }
  25.         }
  26.  
  27.         request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
  28.         request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
  29.         request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
  30.         request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
  31.         if(this.flashMapManager != null) {
  32.             FlashMap inputFlashMap1 = this.flashMapManager.retrieveAndUpdate(request, response);
  33.             if(inputFlashMap1 != null) {
  34.                 request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap1));
  35.             }
  36.  
  37.             request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
  38.             request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
  39.         }
  40.         try {
  41.             this.doDispatch(request, response);
  42.         } finally {
  43.             if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot1 != null) {
  44.                 this.restoreAttributesAfterInclude(request, attributesSnapshot1);
  45.             }
  46.         }
  47.     }

 这个方法里面我们发现定义了一个ModelAndView将要返回的视图与数据,并且首先检测这个请求是不是一个上传的请求,然后根据这个请求获取对应的Handler,如果Handler不为空的话就根据这个handler获取对应的HandlerAdapter。接着调用拦截器链的所有前置拦截的这么一个方法,接着调用adapter的真正的处理方法处理请求,最后调用拦截器链中的所有后置拦截方法。

  1.   protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2.         HttpServletRequest processedRequest = request;
  3.         HandlerExecutionChain mappedHandler = null;
  4.         boolean multipartRequestParsed = false;
  5.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  6.  
  7.         try {
  8.             try {
  9.                 //定义一个空的ModelAndView
  10.                 ModelAndView err = null;
  11.                 Object dispatchException = null;
  12.  
  13.                 try {
  14.                 //检查是否是上传请求
  15.                     processedRequest = this.checkMultipart(request);
  16.                     multipartRequestParsed = processedRequest != request;
  17.                 //获取handler
  18.                     mappedHandler = this.getHandler(processedRequest);
  19.                     if(mappedHandler == null) {
  20.                         this.noHandlerFound(processedRequest, response);
  21.                         return;
  22.                     }
  23.                 //根据handler获取handlerAdapter
  24.                     HandlerAdapter err1 = this.getHandlerAdapter(mappedHandler.getHandler());
  25.                     String method = request.getMethod();
  26.                     boolean isGet = "GET".equals(method);
  27.                     if(isGet || "HEAD".equals(method)) {
  28.                         long lastModified = err1.getLastModified(request, mappedHandler.getHandler());
  29.                         if(this.logger.isDebugEnabled()) {
  30.                             this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
  31.                         }
  32.  
  33.                         if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
  34.                             return;
  35.                         }
  36.                     }
  37.                 //前置拦截
  38.                     if(!mappedHandler.applyPreHandle(processedRequest, response)) {
  39.                         return;
  40.                     }
  41.                 //真正处理
  42.                     err = err1.handle(processedRequest, response, mappedHandler.getHandler());
  43.                     if(asyncManager.isConcurrentHandlingStarted()) {
  44.                         return;
  45.                     }
  46.  
  47.                     this.applyDefaultViewName(processedRequest, err);
  48.                 //后置拦截
  49.                     mappedHandler.applyPostHandle(processedRequest, response, err);
  50.                 } 
  51.                 //后面一些catch finally语句省略。。。。。

 继续跟进这个getHandler方法看看具体是怎么实现的,发现就是循环遍历最开始初始化DispatcherServlet的时候初始化的那7个handlerMapping,去调用这些handlerMapping的getHandler方法;这里我们主要看这个RequestMappingHandlerMapping。

 跟进发现是调用了RequestMappingHandlerMapping的父类AbstractHandlerMapping中的getHandler方法,并且这个方法又是去调用了getHandlerInternal来获取Handler的。

 继续跟进这个getHandlerInternal方法,首先它根据这个request获取它的URI,接着通过uri获取对应的HandlerMethod对象最终返回了。

  1.     protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
  2.         String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
  3.         if(this.logger.isDebugEnabled()) {
  4.             this.logger.debug("Looking up handler method for path " + lookupPath);
  5.         }
  6.  
  7.         this.mappingRegistry.acquireReadLock();
  8.  
  9.         HandlerMethod var4;
  10.         try {
  11.             HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
  12.             if(this.logger.isDebugEnabled()) {
  13.                 if(handlerMethod != null) {
  14.                     this.logger.debug("Returning handler method [" + handlerMethod + "]");
  15.                 } else {
  16.                     this.logger.debug("Did not find handler method for [" + lookupPath + "]");
  17.                 }
  18.             }
  19.  
  20.             var4 = handlerMethod != null?handlerMethod.createWithResolvedBean():null;
  21.         } finally {
  22.             this.mappingRegistry.releaseReadLock();
  23.         }
  24.         return var4;
  25.     }

  跟进这个getLookupPathForRequest发现又调用了getPathWithinServletMapping方法。

 这里我们就知道了这个lookupPath得到的就是这个请求的URI,拿到了这个URI接着就去调用lookupHandlerMethod方法了。

 这里lookupHandlerMethod方法顾名思义就是通过这个URI根据请求的URI去寻找对应的HandlerMethod。

  1.     protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
  2.         ArrayList matches = new ArrayList();
  3.         //通过这个uri去Map中查询与那个HandlerMethod映射
  4.         List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
  5.         if(directPathMatches != null) {
  6.             this.addMatchingMappings(directPathMatches, matches, request);
  7.         }
  8.  
  9.         if(matches.isEmpty()) {
  10.             this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
  11.         }
  12.         //若查询出这个uri有对应的映射关系
  13.         if(!matches.isEmpty()) {
  14.             AbstractHandlerMethodMapping.MatchComparator comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
  15.            //对映射关系排序
  16.             matches.sort(comparator);
  17.             if(this.logger.isTraceEnabled()) {
  18.                 this.logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
  19.             }
  20.             //获取排序后第一个HandlerMethod
  21.             AbstractHandlerMethodMapping.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
  22.             if(matches.size() > 1) {
  23.                 if(CorsUtils.isPreFlightRequest(request)) {
  24.                     return PREFLIGHT_AMBIGUOUS_MATCH;
  25.                 }
  26.  
  27.                 AbstractHandlerMethodMapping.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
  28.                 if(comparator.compare(bestMatch, secondBestMatch) == 0) {
  29.                     Method m1 = bestMatch.handlerMethod.getMethod();
  30.                     Method m2 = secondBestMatch.handlerMethod.getMethod();
  31.                     throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path \'" + request.getRequestURL() + "\': {" + m1 + ", " + m2 + "}");
  32.                 }
  33.             }
  34.  
  35.             this.handleMatch(bestMatch.mapping, lookupPath, request);
  36.             return bestMatch.handlerMethod;
  37.         } else {
  38.             return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
  39.         }
  40.     }

 最终得到了这么一个包含了Handler与这个URI具体处理方法的一个HandlerMethod对象。注意现在这个handler可能还没有被创建出来或者说没有得到,只是知道它的beanName。最终还要调用这么一个createWithResolvedBean方法来得到。

 获得了这个handler之后,又继续根据这个handler获得了HandlerExecutionChain。

  1.    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2.         Object handler = this.getHandlerInternal(request);
  3.         if(handler == null) {
  4.             handler = this.getDefaultHandler();
  5.         }
  6.  
  7.         if(handler == null) {
  8.             return null;
  9.         } else {
  10.             if(handler instanceof String) {
  11.                 String executionChain = (String)handler;
  12.                 handler = this.obtainApplicationContext().getBean(executionChain);
  13.             }
  14.  
  15.             HandlerExecutionChain executionChain1 = this.getHandlerExecutionChain(handler, request);
  16.             if(CorsUtils.isCorsRequest(request)) {
  17.                 CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
  18.                 CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
  19.                 CorsConfiguration config = globalConfig != null?globalConfig.combine(handlerConfig):handlerConfig;
  20.                 executionChain1 = this.getCorsHandlerExecutionChain(request, executionChain1, config);
  21.             }
  22.  
  23.             return executionChain1;
  24.         }
  25.     }

 所以得出最终结论getHandler这个方法最终所有通过这个URI返回了一个最开始注册的handler,然后通过 这个handler返回了一个包含这这个HandlerMethod以及一个拦截器链的这么一个对象。之后执行前置拦截器,handler方法,后置拦截,完成。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值