天天看点

springMVC源码分析--AbstractUrlHandlerMapping(三)

上一篇博客​​springMVC源码分析--AbstractHandlerMapping(二)​​中我们介绍了AbstractHandlerMapping了,接下来我们介绍其子类AbstractUrlHandlerMapping。

springMVC源码分析--AbstractUrlHandlerMapping(三)

在上一篇博客中我们了解到AbstractHandlerMapping提供了一个抽象类getHandlerInternal(HttpServletRequest request),我们首先看看AbstractUrlHandlerMapping中对抽象类getHandlerInternal(HttpServletRequest request)的实现。

//获取Handler,主要是通过url和method的对应关系来查找
  @Override
  protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    //获取request中的请求链接
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    //根据链接查找handler
    Object handler = lookupHandler(lookupPath, request);
    if (handler == null) {
      // We need to care for the default handler directly, since we need to
      // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
      //定义一个变量,保存找到的原始Handler
      Object rawHandler = null;
      if ("/".equals(lookupPath)) {
        rawHandler = getRootHandler();
      }
      if (rawHandler == null) {
        rawHandler = getDefaultHandler();
      }
      if (rawHandler != null) {
        // Bean name or resolved handler?
        //如果是String类型则到容器中查找具体的Bean
        if (rawHandler instanceof String) {
          String handlerName = (String) rawHandler;
          rawHandler = getApplicationContext().getBean(handlerName);
        }
        validateHandler(rawHandler, request);
        handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
      }
    }
    if (handler != null && logger.isDebugEnabled()) {
      logger.debug("Mapping [" + lookupPath + "] to " + handler);
    }
    else if (handler == null && logger.isTraceEnabled()) {
      logger.trace("No handler mapping found for [" + lookupPath + "]");
    }
    return handler;
  }      

从上面的实现方法getHandlerInternal来看,首先是通过lookupHandler方法来查找Handler,这里我们看到了之前说的Map对象,用来存储url和Handler之间的关系,当Handler获取为String时需要从Bean容器中获取注入的实现类,当然在查找过程中也会有模糊匹配等查找过程。

protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    // Direct match?
    //直接从map中获取
    Object handler = this.handlerMap.get(urlPath);
    if (handler != null) {
      // Bean name or resolved handler?
      //如果是String类型则从容器中获取
      if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = getApplicationContext().getBean(handlerName);
      }
      validateHandler(handler, request);
      return buildPathExposingHandler(handler, urlPath, urlPath, null);
    }
    // Pattern match?
    //通过模糊匹配来查找
    List<String> matchingPatterns = new ArrayList<String>();
    for (String registeredPattern : this.handlerMap.keySet()) {
      if (getPathMatcher().match(registeredPattern, urlPath)) {
        matchingPatterns.add(registeredPattern);
      }
      else if (useTrailingSlashMatch()) {
        if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
          matchingPatterns.add(registeredPattern +"/");
        }
      }
    }
    String bestPatternMatch = null;
    //匹配规则
    Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
    if (!matchingPatterns.isEmpty()) {
      Collections.sort(matchingPatterns, patternComparator);
      if (logger.isDebugEnabled()) {
        logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
      }
      bestPatternMatch = matchingPatterns.get(0);
    }
    if (bestPatternMatch != null) {
      handler = this.handlerMap.get(bestPatternMatch);
      if (handler == null) {
        Assert.isTrue(bestPatternMatch.endsWith("/"));
        handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
      }
      // Bean name or resolved handler?
      if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = getApplicationContext().getBean(handlerName);
      }
      validateHandler(handler, request);
      String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);

      // There might be multiple 'best patterns', let's make sure we have the correct URI template variables
      // for all of them
      Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
      for (String matchingPattern : matchingPatterns) {
        if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
          Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
          Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
          uriTemplateVariables.putAll(decodedVars);
        }
      }
      if (logger.isDebugEnabled()) {
        logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
      }
      return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
    }
    // No handler found...
    return null;
  }      

上面两个方法介绍了通过url来查找handlerMap获取handler的操作,AbstractUrlHandlerMapping中也提供了注册url和handler到handlerMap中的操作,具体的调用则要到AbstractUrlHandlerMapping的子类中实现。

//注册url和Bean的map,注册多个string的url到一个处理器中
  protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
    Assert.notNull(urlPaths, "URL path array must not be null");
    for (String urlPath : urlPaths) {
      registerHandler(urlPath, beanName);
    }
  }
  
  注册url和Bean的map,将具体的Handler注入到url对应的map中
  protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
    Assert.notNull(urlPath, "URL path must not be null");
    Assert.notNull(handler, "Handler object must not be null");
    Object resolvedHandler = handler;

    // Eagerly resolve handler if referencing singleton via name.
    //如果Handler是String类型而且没有设置lazyInitHandlers则从springMVC容器中获取handler
    if (!this.lazyInitHandlers && handler instanceof String) {
      String handlerName = (String) handler;
      if (getApplicationContext().isSingleton(handlerName)) {
        resolvedHandler = getApplicationContext().getBean(handlerName);
      }
    }

    Object mappedHandler = this.handlerMap.get(urlPath);
    if (mappedHandler != null) {
      if (mappedHandler != resolvedHandler) {
        throw new IllegalStateException(
            "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
            "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
      }
    }
    else {
      if (urlPath.equals("/")) {
        if (logger.isInfoEnabled()) {
          logger.info("Root mapping to " + getHandlerDescription(handler));
        }
        setRootHandler(resolvedHandler);
      }
      else if (urlPath.equals("/*")) {
        if (logger.isInfoEnabled()) {
          logger.info("Default mapping to " + getHandlerDescription(handler));
        }
        setDefaultHandler(resolvedHandler);
      }
      else {
        this.handlerMap.put(urlPath, resolvedHandler);
        if (logger.isInfoEnabled()) {
          logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
        }
      }
    }
  }      

通过上面介绍我们知道AbstractUrlHandlerMapping提供的功能就是根据url从handlerMap中获取handler和注册url和handler的对应关系到handlerMap中,当然这个过程中还包含很多其他的操作。

AbstractUrlHandlerMapping的完整源码如下:

public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {

  private Object rootHandler;

  private boolean useTrailingSlashMatch = false;

  private boolean lazyInitHandlers = false;

  private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();

  public void setRootHandler(Object rootHandler) {
    this.rootHandler = rootHandler;
  }

  public Object getRootHandler() {
    return this.rootHandler;
  }

  public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
    this.useTrailingSlashMatch = useTrailingSlashMatch;
  }

  public boolean useTrailingSlashMatch() {
    return this.useTrailingSlashMatch;
  }

  public void setLazyInitHandlers(boolean lazyInitHandlers) {
    this.lazyInitHandlers = lazyInitHandlers;
  }
  
  //获取Handler,主要是通过url和method的对应关系来查找
  @Override
  protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    //获取request中的请求链接
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    //根据链接查找handler
    Object handler = lookupHandler(lookupPath, request);
    if (handler == null) {
      // We need to care for the default handler directly, since we need to
      // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
      //定义一个变量,保存找到的原始Handler
      Object rawHandler = null;
      if ("/".equals(lookupPath)) {
        rawHandler = getRootHandler();
      }
      if (rawHandler == null) {
        rawHandler = getDefaultHandler();
      }
      if (rawHandler != null) {
        // Bean name or resolved handler?
        //如果是String类型则到容器中查找具体的Bean
        if (rawHandler instanceof String) {
          String handlerName = (String) rawHandler;
          rawHandler = getApplicationContext().getBean(handlerName);
        }
        validateHandler(rawHandler, request);
        handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
      }
    }
    if (handler != null && logger.isDebugEnabled()) {
      logger.debug("Mapping [" + lookupPath + "] to " + handler);
    }
    else if (handler == null && logger.isTraceEnabled()) {
      logger.trace("No handler mapping found for [" + lookupPath + "]");
    }
    return handler;
  }
  
  protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    // Direct match?
    //直接从map中获取
    Object handler = this.handlerMap.get(urlPath);
    if (handler != null) {
      // Bean name or resolved handler?
      //如果是String类型则从容器中获取
      if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = getApplicationContext().getBean(handlerName);
      }
      validateHandler(handler, request);
      return buildPathExposingHandler(handler, urlPath, urlPath, null);
    }
    // Pattern match?
    //通过模糊匹配来查找
    List<String> matchingPatterns = new ArrayList<String>();
    for (String registeredPattern : this.handlerMap.keySet()) {
      if (getPathMatcher().match(registeredPattern, urlPath)) {
        matchingPatterns.add(registeredPattern);
      }
      else if (useTrailingSlashMatch()) {
        if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
          matchingPatterns.add(registeredPattern +"/");
        }
      }
    }
    String bestPatternMatch = null;
    //匹配规则
    Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
    if (!matchingPatterns.isEmpty()) {
      Collections.sort(matchingPatterns, patternComparator);
      if (logger.isDebugEnabled()) {
        logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
      }
      bestPatternMatch = matchingPatterns.get(0);
    }
    if (bestPatternMatch != null) {
      handler = this.handlerMap.get(bestPatternMatch);
      if (handler == null) {
        Assert.isTrue(bestPatternMatch.endsWith("/"));
        handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
      }
      // Bean name or resolved handler?
      if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = getApplicationContext().getBean(handlerName);
      }
      validateHandler(handler, request);
      String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);

      // There might be multiple 'best patterns', let's make sure we have the correct URI template variables
      // for all of them
      Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
      for (String matchingPattern : matchingPatterns) {
        if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
          Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
          Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
          uriTemplateVariables.putAll(decodedVars);
        }
      }
      if (logger.isDebugEnabled()) {
        logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
      }
      return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
    }
    // No handler found...
    return null;
  }

  protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {
  }

  //用于给找到的Handler注册两个拦截器PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor
  //这两个拦截器的的作用是将与当前url实际匹配的Pattern、匹配条件和url模板参数设置到request的属性中
  protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
      String pathWithinMapping, Map<String, String> uriTemplateVariables) {

    HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
    chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
    if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
      chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
    }
    return chain;
  }

  protected void exposePathWithinMapping(String bestMatchingPattern, String pathWithinMapping, HttpServletRequest request) {
    request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, bestMatchingPattern);
    request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);
  }

  protected void exposeUriTemplateVariables(Map<String, String> uriTemplateVariables, HttpServletRequest request) {
    request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
  }
  
  //注册url和Bean的map,注册多个string的url到一个处理器中
  protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
    Assert.notNull(urlPaths, "URL path array must not be null");
    for (String urlPath : urlPaths) {
      registerHandler(urlPath, beanName);
    }
  }
  
  注册url和Bean的map,将具体的Handler注入到url对应的map中
  protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
    Assert.notNull(urlPath, "URL path must not be null");
    Assert.notNull(handler, "Handler object must not be null");
    Object resolvedHandler = handler;

    // Eagerly resolve handler if referencing singleton via name.
    //如果Handler是String类型而且没有设置lazyInitHandlers则从springMVC容器中获取handler
    if (!this.lazyInitHandlers && handler instanceof String) {
      String handlerName = (String) handler;
      if (getApplicationContext().isSingleton(handlerName)) {
        resolvedHandler = getApplicationContext().getBean(handlerName);
      }
    }

    Object mappedHandler = this.handlerMap.get(urlPath);
    if (mappedHandler != null) {
      if (mappedHandler != resolvedHandler) {
        throw new IllegalStateException(
            "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
            "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
      }
    }
    else {
      if (urlPath.equals("/")) {
        if (logger.isInfoEnabled()) {
          logger.info("Root mapping to " + getHandlerDescription(handler));
        }
        setRootHandler(resolvedHandler);
      }
      else if (urlPath.equals("/*")) {
        if (logger.isInfoEnabled()) {
          logger.info("Default mapping to " + getHandlerDescription(handler));
        }
        setDefaultHandler(resolvedHandler);
      }
      else {
        this.handlerMap.put(urlPath, resolvedHandler);
        if (logger.isInfoEnabled()) {
          logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
        }
      }
    }
  }

  private String getHandlerDescription(Object handler) {
    return "handler " + (handler instanceof String ? "'" + handler + "'" : "of type [" + handler.getClass() + "]");
  }

  public final Map<String, Object> getHandlerMap() {
    return Collections.unmodifiableMap(this.handlerMap);
  }

  protected boolean supportsTypeLevelMappings() {
    return false;
  }

  private class PathExposingHandlerInterceptor extends HandlerInterceptorAdapter {

    private final String bestMatchingPattern;

    private final String pathWithinMapping;

    public PathExposingHandlerInterceptor(String bestMatchingPattern, String pathWithinMapping) {
      this.bestMatchingPattern = bestMatchingPattern;
      this.pathWithinMapping = pathWithinMapping;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
      exposePathWithinMapping(this.bestMatchingPattern, this.pathWithinMapping, request);
      request.setAttribute(HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING, supportsTypeLevelMappings());
      return true;
    }

  }
  
  private class UriTemplateVariablesHandlerInterceptor extends HandlerInterceptorAdapter {

    private final Map<String, String> uriTemplateVariables;

    public UriTemplateVariablesHandlerInterceptor(Map<String, String> uriTemplateVariables) {
      this.uriTemplateVariables = uriTemplateVariables;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
      exposeUriTemplateVariables(this.uriTemplateVariables, request);
      return true;
    }
  }

}      

继续阅读