Spring MVC源码和设计思想2 HandlerMapping

  created  by  鱼鱼 {{tag}}
创建于 2019年06月03日 19:09:41 最后修改于 2019年06月12日 23:32:05

系列传送门Spring MVC源码和设计思想1  DispatcherServlet-鱼鱼的博客

综述

    此篇篇幅很长,且慢慢道来。

    在之前一篇中,DispatchServlet的doDispatch()方法中有这么几行:

HandlerExecutionChain mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
    noHandlerFound(processedRequest, response);
    return;
}

    其中getHandler方法:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) {
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

    handlerMappings是一个初始化过的List<HandlerMapping>,通过它获取HandlerExecutionChain。HandlerExecutionChain存储了一个Object(其实就是HandleAdapter)和一个拦截器(HandlerInterceptor)数组,在doDispatch方法中执行了applyPreHandle和applyPostHandle方法,方法就是分别迭代调用了拦截器数组的postHandle和preHandle,同样地,发生异常时的triggerAfterCompletion也映射到了afterCompletion方法。

    HanddlerMapping是非常简单的接口,只定义了一个getHandler方法,通过request选择对应的Handler。

    HanddlerMapping的基本实现是抽象类AbstractHandlerMapping。相关类图:

AbstractHandlerMapping

        继承了HandlerMapping的方法如下:

// AbstractHandlerMapping.java

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 获得Handler,该方法是模板方法
    Object handler = getHandlerInternal(request);
    // 获取失败使用默认处理器,一般不会发生这种情况
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    // String的Handler
        if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    // 1 获得HandlerExecutionChain对象
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    // 打印日志
    if (logger.isTraceEnabled()) {
        logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        logger.debug("Mapped to " + executionChain.getHandler());
    }

    // 跨域
    if (hasCorsConfigurationSource(handler)) {
        CorsConfiguration config = (this.corsConfigurationSource != null ? 
                    this.corsConfigurationSource.getCorsConfiguration(request) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
  
    return executionChain;
}

继承他的类主要便是依靠重写getHandlerInternal方法实现对应的功能。

    1处的方法代码:

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
    //获取请求路径
   String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    //遍历拦截器数组,匹配添加 
    相应的拦截器
   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;
}

AbstractHandlerMethodMapping

        首先看最关键的方法重写,会返回HandlerMethod方法    

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //获得请求路径
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   
   request.setAttribute(LOOKUP_PATH, lookupPath);
   //获得写锁
   this.mappingRegistry.acquireReadLock();
   try {
           //1
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }
   finally {
       //释放锁
      this.mappingRegistry.releaseReadLock();
   }
}

lookupHandlerMethod()

        1处调用了这一方法,

@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
   List<Match> matches = new ArrayList<>();
   List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
   if (directPathMatches != null) {
      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()) {
      Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
      matches.sort(comparator);
      Match bestMatch = matches.get(0);
      if (matches.size() > 1) {
         if (logger.isTraceEnabled()) {
            logger.trace(matches.size() + " matching mappings: " + matches);
         }
         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();
            String uri = request.getRequestURI();
            throw new IllegalStateException(
                  "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
         }
      }
      request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
      handleMatch(bestMatch.mapping, lookupPath, request);
      return bestMatch.handlerMethod;
   }
   else {
      return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
   }
}

        在解释之前,我们需要看MappingRegistry中的相应方法。

MappingRegistry

        MappingRegistry是AbstractHandlerMethodMapping的私有类,主要负责Mapping的注册。其中在上文中调用的锁处理在这里就略过,其实就是一个ReentrantReadWriteLock对象。

        下面过一下方法和变量:

private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

protected HandlerMethod createHandlerMethod(Object handler, Method method) {
   if (handler instanceof String) {
      return new HandlerMethod((String) handler,
            obtainApplicationContext().getAutowireCapableBeanFactory(), method);
   }
   return new HandlerMethod(handler, method);
}

public void register(T mapping, Object handler, Method method) {
   this.readWriteLock.writeLock().lock();
   try {
      HandlerMethod handlerMethod = createHandlerMethod(handler, method);
      //校验mapping,需要为空才可以
      validateMethodMapping(handlerMethod, mapping);
      this.mappingLookup.put(mapping, handlerMethod);
        //mapping-url对应
      List<String> directUrls = getDirectUrls(mapping);
      for (String url : directUrls) {
         this.urlLookup.add(url, mapping);
      }

      String name = null;
      if (getNamingStrategy() != null) {
         name = getNamingStrategy().getName(handlerMethod, mapping);
         addMappingName(name, handlerMethod);
      }

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

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

       其中调用了createWithResolvedBean方法:

public HandlerMethod createWithResolvedBean() {
   Object handler = this.bean;
   if (this.bean instanceof String) {
      Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
      String beanName = (String) this.bean;
      handler = this.beanFactory.getBean(beanName);
   }
   return new HandlerMethod(this, handler);
}

        初始化内容 关键定义如下:

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    @Override
    public void afterPropertiesSet() {
       initHandlerMethods();
    }
    
   protected void initHandlerMethods() {
       for (String beanName : getCandidateBeanNames()) {
          if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
             processCandidateBean(beanName);
          }
       }
       handlerMethodsInitialized(getHandlerMethods());
    }
}

tip:InitializingBean接口

        AbstractHandlerMethodMapping方法继承了InitizlizingBean接口,其唯一的方法afterPropertiesSet()将会在继承他的类bean被初始化的时候执行,并且先于init方法执行。

HandlerMapping的初始化

评论区
评论
{{comment.creator}}
{{comment.createTime}} {{comment.index}}楼
评论

Spring MVC源码和设计思想2 HandlerMapping

Spring MVC源码和设计思想2 HandlerMapping

系列传送门Spring MVC源码和设计思想1  DispatcherServlet-鱼鱼的博客

综述

    此篇篇幅很长,且慢慢道来。

    在之前一篇中,DispatchServlet的doDispatch()方法中有这么几行:

HandlerExecutionChain mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
    noHandlerFound(processedRequest, response);
    return;
}

    其中getHandler方法:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) {
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

    handlerMappings是一个初始化过的List<HandlerMapping>,通过它获取HandlerExecutionChain。HandlerExecutionChain存储了一个Object(其实就是HandleAdapter)和一个拦截器(HandlerInterceptor)数组,在doDispatch方法中执行了applyPreHandle和applyPostHandle方法,方法就是分别迭代调用了拦截器数组的postHandle和preHandle,同样地,发生异常时的triggerAfterCompletion也映射到了afterCompletion方法。

    HanddlerMapping是非常简单的接口,只定义了一个getHandler方法,通过request选择对应的Handler。

    HanddlerMapping的基本实现是抽象类AbstractHandlerMapping。相关类图:

AbstractHandlerMapping

        继承了HandlerMapping的方法如下:

// AbstractHandlerMapping.java

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 获得Handler,该方法是模板方法
    Object handler = getHandlerInternal(request);
    // 获取失败使用默认处理器,一般不会发生这种情况
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    // String的Handler
        if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    // 1 获得HandlerExecutionChain对象
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    // 打印日志
    if (logger.isTraceEnabled()) {
        logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        logger.debug("Mapped to " + executionChain.getHandler());
    }

    // 跨域
    if (hasCorsConfigurationSource(handler)) {
        CorsConfiguration config = (this.corsConfigurationSource != null ? 
                    this.corsConfigurationSource.getCorsConfiguration(request) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
  
    return executionChain;
}

继承他的类主要便是依靠重写getHandlerInternal方法实现对应的功能。

    1处的方法代码:

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
    //获取请求路径
   String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    //遍历拦截器数组,匹配添加 
    相应的拦截器
   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;
}

AbstractHandlerMethodMapping

        首先看最关键的方法重写,会返回HandlerMethod方法    

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //获得请求路径
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   
   request.setAttribute(LOOKUP_PATH, lookupPath);
   //获得写锁
   this.mappingRegistry.acquireReadLock();
   try {
           //1
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }
   finally {
       //释放锁
      this.mappingRegistry.releaseReadLock();
   }
}

lookupHandlerMethod()

        1处调用了这一方法,

@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
   List<Match> matches = new ArrayList<>();
   List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
   if (directPathMatches != null) {
      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()) {
      Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
      matches.sort(comparator);
      Match bestMatch = matches.get(0);
      if (matches.size() > 1) {
         if (logger.isTraceEnabled()) {
            logger.trace(matches.size() + " matching mappings: " + matches);
         }
         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();
            String uri = request.getRequestURI();
            throw new IllegalStateException(
                  "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
         }
      }
      request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
      handleMatch(bestMatch.mapping, lookupPath, request);
      return bestMatch.handlerMethod;
   }
   else {
      return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
   }
}

        在解释之前,我们需要看MappingRegistry中的相应方法。

MappingRegistry

        MappingRegistry是AbstractHandlerMethodMapping的私有类,主要负责Mapping的注册。其中在上文中调用的锁处理在这里就略过,其实就是一个ReentrantReadWriteLock对象。

        下面过一下方法和变量:

private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

protected HandlerMethod createHandlerMethod(Object handler, Method method) {
   if (handler instanceof String) {
      return new HandlerMethod((String) handler,
            obtainApplicationContext().getAutowireCapableBeanFactory(), method);
   }
   return new HandlerMethod(handler, method);
}

public void register(T mapping, Object handler, Method method) {
   this.readWriteLock.writeLock().lock();
   try {
      HandlerMethod handlerMethod = createHandlerMethod(handler, method);
      //校验mapping,需要为空才可以
      validateMethodMapping(handlerMethod, mapping);
      this.mappingLookup.put(mapping, handlerMethod);
        //mapping-url对应
      List<String> directUrls = getDirectUrls(mapping);
      for (String url : directUrls) {
         this.urlLookup.add(url, mapping);
      }

      String name = null;
      if (getNamingStrategy() != null) {
         name = getNamingStrategy().getName(handlerMethod, mapping);
         addMappingName(name, handlerMethod);
      }

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

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

       其中调用了createWithResolvedBean方法:

public HandlerMethod createWithResolvedBean() {
   Object handler = this.bean;
   if (this.bean instanceof String) {
      Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
      String beanName = (String) this.bean;
      handler = this.beanFactory.getBean(beanName);
   }
   return new HandlerMethod(this, handler);
}

        初始化内容 关键定义如下:

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    @Override
    public void afterPropertiesSet() {
       initHandlerMethods();
    }
    
   protected void initHandlerMethods() {
       for (String beanName : getCandidateBeanNames()) {
          if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
             processCandidateBean(beanName);
          }
       }
       handlerMethodsInitialized(getHandlerMethods());
    }
}

tip:InitializingBean接口

        AbstractHandlerMethodMapping方法继承了InitizlizingBean接口,其唯一的方法afterPropertiesSet()将会在继承他的类bean被初始化的时候执行,并且先于init方法执行。

HandlerMapping的初始化


Spring MVC源码和设计思想2 HandlerMapping2019-06-12鱼鱼

{{commentTitle}}

评论   ctrl+Enter 发送评论