springmvc源码笔记-RequestMappingHandlerMapping

2022年6月16日 348点热度 0人点赞 0条评论
  1. 下图是springmvc的执行流程

    5220087-3c0f59d3c39a12dd

    图片来源:https://www.jianshu.com/p/8a20c547e245


    DispatcherServlet根据url定位到Controller和方法,依赖的是HandlerMapping接口的各个实现类,其中,RequestMappingHandlerMapping是专门用来处理注解方式的Controller的
    

    下面,我们分RequestMappingHandlerMapping的加载以及RequestMappingHandlerMapping如何根据url定位Controller两部分来讲

    RequestMappingHandlerMapping加载过程

    1. RMHP在系统启动时会被注册成bean,见《springmvc源码笔记-HandlerMapping注入》

    2. 因为RMHP实现了InitializingBean接口,在bean加载完成后会自动调用afterPropertiesSet方法,在此方法中调用了AbstractHandlerMethodMapping#initHandlerMethods()来实现初始化

      protected void initHandlerMethods() {
      // 遍历所有的bean
      for (String beanName : getCandidateBeanNames()) {
          if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
              processCandidateBean(beanName);
          }
      }
      handlerMethodsInitialized(getHandlerMethods());
      }
      
      protected void processCandidateBean(String beanName) {
      Class<?> beanType = null;
      try {
          beanType = obtainApplicationContext().getType(beanName);
      }
      ......
      // isHandler判断类是否有Controller或者RequestMapping注解
      if (beanType != null && isHandler(beanType)) {
          detectHandlerMethods(beanName);
      }
      }
      
      protected void detectHandlerMethods(Object handler) {
      ......
      if (handlerType != null) {
          Class<?> userType = ClassUtils.getUserClass(handlerType);
          // 遍历类的所有方法
          Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                  (MethodIntrospector.MetadataLookup<T>) method -> {
                      try {
                          // 获取方法上的映射(会读取方法上的RequestMapping注解获取url)
                          return getMappingForMethod(method, userType);
                      }
                      catch (Throwable ex) {
                          throw new IllegalStateException("Invalid mapping on handler class [" +
                                  userType.getName() + "]: " + method, ex);
                      }
                  });
          ......
          methods.forEach((method, mapping) -> {
              Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
              // 将映射关系放入AbstractHandlerMethodMapping.mappingRegistry中
              registerHandlerMethod(handler, invocableMethod, mapping);
          });
      }
      }
      

    RequestMappingHandlerMapping解析过程

    1. DispatcherServlet继承HttpServlet,所以执行链是FrameworkServlet#doGet→DispatcherServlet#doService→DispatcherServlet#doDispatch→DispatcherServlet#getHandler
      protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
      if (this.handlerMappings != null) {
          // handlerMappings已在onRefresh方法中初始化
          for (HandlerMapping mapping : this.handlerMappings) {
              // 第一个mapping就是RequestMappingHandlerMapping
              // 获取处理程序,也就是url对应的controller和method
              HandlerExecutionChain handler = mapping.getHandler(request);
              if (handler != null) {
                  return handler;
              }
          }
      }
      return null;
      }
      
      // AbstractHandlerMapping#getHandler->RequestMappingHandlerMapping#getHandlerInternal->AbstractHandlerMapping#lookupHandlerMethod
      protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
      // lookupPath就是请求路径
      List<Match> matches = new ArrayList<>();
      // 获取url路径匹配项
      List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
      if (directPathMatches != null) {
          // 添加映射匹配集合
          addMatchingMappings(directPathMatches, matches, request);
      }
      if (matches.isEmpty()) {
          addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
      }
      if (!matches.isEmpty()) {
          ......
          // 至此,根据url获取到controller和method
          return bestMatch.getHandlerMethod();
      } else {
          return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
      }
      }
      
      private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
      for (T mapping : mappings) {
          T match = getMatchingMapping(mapping, request);
          if (match != null) {
              // this.mappingRegistry.getRegistrations().get(mapping)就是获取HandlerMethodMapping
              // HandlerMethodMapping保存controller和method信息的类
              matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
          }
      }
      }
      

王谷雨

一个苟且偷生的java程序员

文章评论