SpringMVC的Handler初始化及獲取

HandlerMethod類 |註冊Handler

InvocableHandlerMethod

對請求進行處理html

  • WebDataBinderFactory
  • HandlerMethodArgumentResolverComposite

ServletInvocableHandlerMethod

處理返回值java

  • HandlerMethodReturnValueHandlerComposite

MethodParameter[] parameters

封裝了參數信息:參數的的索引位置,類型,註解,參數名等信息git

RequestCondition

各類condition,其中RequestMappingInfo相似代理類,相似condition集合。web

AbStractHandlerMethodMapping

AbstractHandlerMethodMapping implements InitializingBeanspring

初始化階段會執行afterPropertiesSet() 方法。mvc

@Override
public void afterPropertiesSet() {
   initHandlerMethods();
}

initHandlerMethods()

從ApplicationContext中檢測,註冊HandlerMethodsapp

/**
 * Scan beans in the ApplicationContext, detect and register handler methods.
 * @see #isHandler(Class)
 * @see #getMappingForMethod(Method, Class)
 * @see #handlerMethodsInitialized(Map)
 */
protected void initHandlerMethods() {
    if (logger.isDebugEnabled()) {
        logger.debug("Looking for request mappings in application context: " + getApplicationContext());
    }
    //找出容器中的全部類。
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
                          BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                          getApplicationContext().getBeanNamesForType(Object.class));

    for (String beanName : beanNames) {
        //排除scopedTarget.開頭的bean
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            Class<?> beanType = null;
            try {
                beanType = getApplicationContext().getType(beanName);
            }
            catch (Throwable ex) {
                // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                }
            }
            //isHandler()檢測是不是handler,模版方法
            //RequestMappingHandlerMapping.isHandler() 判斷是不是@controller 或者 @RequestMapping
            if (beanType != null && isHandler(beanType)) {
                //查找HandlerMethods
                detectHandlerMethods(beanName);
            }
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}

detectHandlerMethods()

/**
 * Look for handler methods in a handler.
 * @param handler the bean name of a handler or a handler instance
 */
//傳進來的是beanName
protected void detectHandlerMethods(final Object handler) {
   Class<?> handlerType = (handler instanceof String ?
         getApplicationContext().getType((String) handler) : handler.getClass());
    //針對CGLIB生成的子類,找到真正用戶定義的類型userType
   final Class<?> userType = ClassUtils.getUserClass(handlerType);

    //從Class中獲取<Method,RequestMappingInfo>
   Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
         new MethodIntrospector.MetadataLookup<T>() {
            @Override
            public T inspect(Method method) {
               try {
                  //RequestMappingHandlerMapping.getMappingForMethod(),構造getMappingForMethod
                  //
                  return getMappingForMethod(method, userType);
               }
               catch (Throwable ex) {
                  throw new IllegalStateException("Invalid mapping on handler class [" +
                        userType.getName() + "]: " + method, ex);
               }
            }
         });

   if (logger.isDebugEnabled()) {
      logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
   }
   for (Map.Entry<Method, T> entry : methods.entrySet()) {
       //判斷Method是否可調用(不是private方法)
      Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
       //RequestMappingInfo(方法上的信息)
      T mapping = entry.getValue();
       //註冊到AbstractHandlerMethodMapping.MappingRegistry屬性中。
      registerHandlerMethod(handler, invocableMethod, mapping);
   }
}

RequestMappingHandlerMapping.getMappingForMethod()

用來創造RequestMappingInfo的cors

/**
 * Uses method and type-level @{@link RequestMapping} annotations to create
 * the RequestMappingInfo.
 * @return the created RequestMappingInfo, or {@code null} if the method
 * does not have a {@code @RequestMapping} annotation.
 * @see #getCustomMethodCondition(Method)
 * @see #getCustomTypeCondition(Class)
 */
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    //先從method中獲取info
   RequestMappingInfo info = createRequestMappingInfo(method);
   if (info != null) {
       //不爲空,再從Class中獲取Info
      RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
      if (typeInfo != null) {
          //最後combine
         info = typeInfo.combine(info);
      }
   }
   return info;
}
RequestMappingHandlerMapping.createRequestMappingInfo
/**
 * Delegates to {@link #createRequestMappingInfo(RequestMapping, RequestCondition)},
 * supplying the appropriate custom {@link RequestCondition} depending on whether
 * the supplied {@code annotatedElement} is a class or method.
 * @see #getCustomTypeCondition(Class)
 * @see #getCustomMethodCondition(Method)
 */
//獲取RequestMappingInfo
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
   RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
    //獲取自定義Condition,能夠自定義,參見https://app.yinxiang.com/shard/s47/nl/20202808/83224da8-631d-4d1a-a586-9ac56564d74b
   RequestCondition<?> condition = (element instanceof Class ?
         getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
    //主要就是將@RequestMapping中大部分信息設置到RequestMappingInfo中
    //而且構造各類condition,
   return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
AbstractHandlerMethodMapping.register

設計到的MappingRegistry中的Mapide

//<RequestMappingInfo,MappingRegistration>
private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();

//<RequestMappingInfo,HandlerMethod>
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();

//<url,RequestMappingInfo>
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();

//RequestMappingInfo.Name或HandlerMethod的name, List<HandlerMethod>
private final Map<String, List<HandlerMethod>> nameLookup =
      new ConcurrentHashMap<String, List<HandlerMethod>>();

private final Map<HandlerMethod, CorsConfiguration> corsLookup =
      new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();
//註冊mapping是RequestMappingInfo
public void register(T mapping, Object handler, Method method) {
   this.readWriteLock.writeLock().lock();
   try {
       //構造HandlerMethod
      HandlerMethod handlerMethod = createHandlerMethod(handler, method);
       //確認惟一的mapping
      assertUniqueMethodMapping(handlerMethod, mapping);

      if (logger.isInfoEnabled()) {
         logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
      }
       //放入mappingLookup中,<RequestMappingInfo,HandlerMethod>
      this.mappingLookup.put(mapping, handlerMethod);

       //獲取url,從RequestMappingInfo的PatternsCondition中獲取。
      List<String> directUrls = getDirectUrls(mapping);
      for (String url : directUrls) {
          //<url,RequestMappingInfo>
         this.urlLookup.add(url, mapping);
      }

      String name = null;
      if (getNamingStrategy() != null) {
          //命名策略
          // For example "TC#getFoo" * for a class named TestController with method getFoo.
          //RequestMappingInfo的name不爲空則返回其name,若是爲空,按照命名策略定義一個名字,例如「TC#foo」
         name = getNamingStrategy().getName(handlerMethod, mapping);
          //this.nameLookup.put(name, List<HandlerMethod>);
         addMappingName(name, handlerMethod);
      }

      CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
      if (corsConfig != null) {
         this.corsLookup.put(handlerMethod, corsConfig);
      }

       //<RequestMappingInfo,MappingRegistration>
      this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
   }
   finally {
      this.readWriteLock.writeLock().unlock();
   }
}

RequestMappingHandlerMapping

/**
 * Creates {@link RequestMappingInfo} instances from type and method-level
 * {@link RequestMapping @RequestMapping} annotations in
 * {@link Controller @Controller} classes.
 */

DispatcherServlet() | 獲取Handler

protected void doDispatch(HttpServletRequest request, HttpServletResponse response){
    ...
    mappedHandler = getHandler(processedRequest);
    ...
}

getHandler中使用DispatcherServlet 中配置的 List<HandlerMapping> handlerMappings;來獲取handlerui

//org.springframework.web.servlet.DispatcherServlet#getHandler
HandlerExecutionChain handler = hm.getHandler(request);

AbstractHandlerMapping#getHandler()

HandlerMapping的getHandler()方法由抽象類AbstractHandlerMapping實現

@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //根據request獲取handler,此處handler是handlerMethod
   Object handler = getHandlerInternal(request);
   if (handler == null) {
      handler = getDefaultHandler();
   }
   if (handler == null) {
      return null;
   }
   // Bean name or resolved handler?
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = getApplicationContext().getBean(handlerName);
   }
    //獲取執行鏈
   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
   if (CorsUtils.isCorsRequest(request)) {
      CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }
   return executionChain;
}

getHandlerInternal(request);爲AbstractHandlerMapping的抽象方法

AbstractHandlerMapping類繼承關係

AbstractHandlerMethodMapping 和 AbstractUrlHandlerMapping

AbstractHandlerMethodMapping#getHandlerInternal()

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //獲取path,從request獲取contextPath + RequestUri + RemainingPath
    /**
     * Return the path within the servlet mapping for the given request,
     * i.e. the part of the request's URL beyond the part that called the servlet,
     * or "" if the whole URL has been used to identify the servlet.
     * <p>Detects include request URL if called within a RequestDispatcher include.
     * <p>E.g.: servlet mapping = "/*"; request URI = "/test/a" -> "/test/a".
     * <p>E.g.: servlet mapping = "/"; request URI = "/test/a" -> "/test/a".
     * <p>E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a".
     * <p>E.g.: servlet mapping = "/test"; request URI = "/test" -> "".
     * <p>E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "".
     * @param request current HTTP request
     * @return the path within the servlet mapping, or ""
     */
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    if (logger.isDebugEnabled()) {
        logger.debug("Looking up handler method for path " + lookupPath);
    }
    //加讀鎖
    this.mappingRegistry.acquireReadLock();
    try {
        //根據path找HandlerMethod
        // 從mappingRegistry.urlLookup()中根據url找到對應的List<RequestMappingInfo>
        //遍歷 RequestMappingInfo,RequestMappingInfo中有各類condition,根據requst看各個RequestMappingInfo與requst是否匹配,匹配的話構造一個新的RequestMappingInfo返回。
        //根據新構造的RequestMappingInfo和從mappingRegistry.getMappings中根據request獲取的HandleMehtod,構造Match對象,並加入到List<Match>中。
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);//↓
        if (logger.isDebugEnabled()) {
            if (handlerMethod != null) {
                logger.debug("Returning handler method [" + handlerMethod + "]");
            }
            else {
                logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        //釋放鎖
        this.mappingRegistry.releaseReadLock();
    }
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<Match>();
    //url -> RequestMappingInfo (從urlLookup中),多值map
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        //directPathMatche就是RequestMappingInfo
        //(directPathMatche,request) -> new RequestMappingInfo() //檢測是否全部的condition 與提供的request匹配。
        //mappingRegistry.mappingLookup().get(directPathMatche) -> HandleMethod (this.mappingLookup)
        //(new RequestMappingInfo(),HandleMethod) -> Match -> List<Match>
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // No choice but to go through all mappings...
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    if (!matches.isEmpty()) {
        //構造比較器,比較方法最終調用各個condition的compare方法
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
        Collections.sort(matches, comparator);
        if (logger.isTraceEnabled()) {
            logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
                         lookupPath + "] : " + matches);
        }
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            //兩個相同拋異常,不知道用哪一個
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
                                                request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
            }
        }
        //將匹配的LookupPath放入request中?有啥用?
        handleMatch(bestMatch.mapping, lookupPath, request);
        //Match中有HandlerMethod,返回對應的HandlerMethod
        return bestMatch.handlerMethod;
    }
    else {
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

AbstractHandlerMapping#getHandlerExecutionChain

/**
 * Build a {@link HandlerExecutionChain} for the given handler, including
 * applicable interceptors.
 * <p>The default implementation builds a standard {@link HandlerExecutionChain}
 * with the given handler, the handler mapping's common interceptors, and any
 * {@link MappedInterceptor}s matching to the current request URL. Interceptors
 * are added in the order they were registered. Subclasses may override this
 * in order to extend/rearrange the list of interceptors.
 * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
 * pre-built {@link HandlerExecutionChain}. This method should handle those
 * two cases explicitly, either building a new {@link HandlerExecutionChain}
 * or extending the existing chain.
 * <p>For simply adding an interceptor in a custom subclass, consider calling
 * {@code super.getHandlerExecutionChain(handler, request)} and invoking
 * {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
 * @param handler the resolved handler instance (never {@code null})
 * @param request current HTTP request
 * @return the HandlerExecutionChain (never {@code null})
 * @see #getAdaptedInterceptors()
 */
//主要就是給handler設置interceptor
//傳入的handler多是handler(HandlerMethod)或者HandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

   String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
   for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
      if (interceptor instanceof MappedInterceptor) {
         MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
         if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
            chain.addInterceptor(mappedInterceptor.getInterceptor());
         }
      }
      else {
         chain.addInterceptor(interceptor);
      }
   }
   return chain;
}

資源文件映射

<mvc:resources location="/static/" mapping="/static/**"/>

Spring 使用 ResourcesBeanDefinitionParser 解析 xml 實例化SimpleUrlHandlerMapping,註冊handlerMethod爲ResourceHttpRequestHandler。

ResourceHttpRequestHandler進行handleRequest的時候,直接輸出資源文件的文本內容。

Reference

相關文章
相關標籤/搜索