spring mvc 方法映射原理解析(二)

1.源码版本

spring-mvc 4.3.9

2.回顾

通过源码分析一可以看到 , 在DispatcherServlet的doDispatch方法中,有一个很重要的方法,就是通过request获取

当前请求的handler , 这个handler就是我们请求的那个方法的封装。 这里主要说一下,spring mvc是如何对Controller

进行初始化,以及http请求过来之后,是怎么通过通过请求URL找到相应的请求的。

3.AbstractHandlerMethodMapping

主要是看这个类,该类里面对Controller的方法进行的初始化,以及映射关系的查找

public void afterPropertiesSet() {
	// 加载完该BEAN之后,调用initHandlerMethods方法。进行初始化
   initHandlerMethods();
}


protected void initHandlerMethods() {
   if (logger.isDebugEnabled()) {
      logger.debug("Looking for request mappings in application context: " + getApplicationContext());
   }
   // 获取spring容器里面所有的beanName
   String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
         BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
         getApplicationContext().getBeanNamesForType(Object.class));
   // 遍历beanName
   for (String beanName : beanNames) {
      // 如果是scopedTarget.这个开头的bean, 则不做处理。
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
         Class<?> beanType = null;
         try {
			// 获取bean类型
            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);
            }
         }
         // 如果beanType 不为空,并且isHandler为true
         if (beanType != null && isHandler(beanType)) {
			// 对方法进行处理
            detectHandlerMethods(beanName);
         }
      }
   }
   handlerMethodsInitialized(getHandlerMethods());
}

从上面可以看到,在决定是否要处理该BEAN时,有个isHandler 方法 , 该方法主要就是判断这个类上面是否有@Controller获取@RequestMapping注解

@Override
protected boolean isHandler(Class<?> beanType) {
   return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
         AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}


detectHandlerMethods主要是将这个类所有带有@RequestMappering的方法收集起来、
protected void detectHandlerMethods(final Object handler) {
  // 判断handler是对象还是字符串,如果是字符串则从容器里面去拿
   Class<?> handlerType = (handler instanceof String ?
         getApplicationContext().getType((String) handler) : handler.getClass());
   final Class<?> userType = ClassUtils.getUserClass(handlerType);

  // 筛选方法
   Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
         new MethodIntrospector.MetadataLookup<T>() {
            @Override
            public T inspect(Method method) {
               try {
   					// 主要是看这个方法
                  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);
   }
   // 遍历所有带有@RequestMapping的方法 , 以method为key , requestMappingInfo为value
   for (Map.Entry<Method, T> entry : methods.entrySet()) {
      Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
      T mapping = entry.getValue();
	  // 注册方法,将方法映射信息放入内存
      registerHandlerMethod(handler, invocableMethod, mapping);
   }
}



@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
	// 创建RequestMappingInfo
   RequestMappingInfo info = createRequestMappingInfo(method);
   if (info != null) {
      RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
      if (typeInfo != null) {
         info = typeInfo.combine(info);
      }
   }
   return info;
}


private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
   // 获取该方法中的RequestMapping 信息
   RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
   RequestCondition<?> condition = (element instanceof Class ?
         getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
  // 如果能找到RequestMapping 那么则构建RequestMappingInfo实体信息返回,没有则返回空
   return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

通过上面的源码分析 我们可以看到detectHandlerMethods调用到最后,是调用了registerHandlerMethod

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
   this.mappingRegistry.register(mapping, handler, method);
}
MappingRegistry 是 AbstractHandlerMethodMapping的一个内部类,上面是通过this.mappingRegistry这个属性

调用该内部类中的register方法,将该方法注册到映射注册中心去,


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>();
// name和HandlerMethod的关系
private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<String, List<HandlerMethod>>();
// 方法和跨域信息的映射
private final Map<HandlerMethod, CorsConfiguration> corsLookup =
      new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();

private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();




public void register(T mapping, Object handler, Method method) {
	// 上锁因为registry , mappingLookup , urlLookup 这两个LinkedHashMap是非线程安全的
   this.readWriteLock.writeLock().lock();
   try {
	  构建handlerMethod 
      HandlerMethod handlerMethod = createHandlerMethod(handler, method);
      assertUniqueMethodMapping(handlerMethod, mapping);

      if (logger.isInfoEnabled()) {
         logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
      }
	  // 将requestMappingInfo为键,handlerMethod为value,放入linkedHashMap
      this.mappingLookup.put(mapping, handlerMethod);

	  // 获取该方法上的url地址,
      List<String> directUrls = getDirectUrls(mapping);
      for (String url : directUrls) {
	    // 将请求映射的URL放入LinkedMultiValueMap , 一个key对应多个value
		// 防止出现比如同一个URL,有一个是GET 请求,一个是给POST的请求的
		// 那样就会出现同一个url对应多个RequestMappingInfo的情况
         this.urlLookup.add(url, mapping);
      }
	  //spring mvc 4.x以后,可以通过配置name属性来方位该方法,次数就是为了完成这个操作
      String name = null;
      if (getNamingStrategy() != null) {
		// 
         name = getNamingStrategy().getName(handlerMethod, mapping);
         addMappingName(name, handlerMethod);
      }
	  // 处理跨域请求的注解,如果某个method上用了@CrossOrigin这个注解
      CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
      if (corsConfig != null) {
		 // 如果不为空,那么将这个方法对应的跨域 信息放入map中
         this.corsLookup.put(handlerMethod, corsConfig);
      }

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


protected HandlerMethod createHandlerMethod(Object handler, Method method) {
   HandlerMethod handlerMethod;
   if (handler instanceof String) {
      String beanName = (String) handler;
      handlerMethod = new HandlerMethod(beanName,
            getApplicationContext().getAutowireCapableBeanFactory(), method);
   }
   else {
      handlerMethod = new HandlerMethod(handler, method);
   }
   // 这个HandlerMethod里面包含了大量的信息,bean, beanFactory, beanType,method ,parameters 等等
   return handlerMethod;
}

DispatcherServlet的getHandler

最终我们回调dispatcherServlet这个类里面来,这个过滤器里面通过request获取Handler

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   for (HandlerMapping hm : this.handlerMappings) {
      if (logger.isTraceEnabled()) {
         logger.trace(
               "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
      }
      // 获取Handler执行链
      HandlerExecutionChain handler = hm.getHandler(request);
      if (handler != null) {
         return handler;
      }
   }
   return null;
}


直接看gethandler方法

@Override
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?
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = getApplicationContext().getBean(handlerName);
   }
   // 获取handler的执行链,主要是把拦截器的执行也构建在了这个方法里面
   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这个方法是个抽象方法,具体实现在AbstractHandlerMethodMapping 

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
   //获取请求路径
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   if (logger.isDebugEnabled()) {
      logger.debug("Looking up handler method for path " + lookupPath);
   }
   // 上锁因为这个类里面的map很多是非线程安全的
   this.mappingRegistry.acquireReadLock();
   try {
     // 重点在这里
      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,从对应的映射map里面获取requestMappingInfo
   List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
   if (directPathMatches != null) {
	  // 该方法会对requestMappingInfo中的各种条件做匹配,如果匹配对了,则放入matches
      addMatchingMappings(directPathMatches, matches, request);
   }
   if (matches.isEmpty()) {
      // No choice but to go through all mappings...
      // 没有匹配到,则遍历所有的requestMappingInfo ,期望能找到一个
      addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
   }

   if (!matches.isEmpty()) {
	  // 比较找到的matches , 通过requestMappingInfo中的compareTo进行排序
      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 + "}");
         }
      }
       // 返回找到的handler
      handleMatch(bestMatch.mapping, lookupPath, request);
      return bestMatch.handlerMethod;
   }
   else {
      // 返回NoMatch ,匹配失败
      return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
   }
}





猜你喜欢

转载自blog.csdn.net/u012394095/article/details/80169122