Spring源码学习28

DispatcherServlet.doDispatch方法的getHandler(request)方法

/**
     * 返回此请求的HandlerExecutionChain。
     * <p>按顺序尝试所有处理程序映射。
     *
     * @param request current HTTP request
     * @return the HandlerExecutionChain, or {@code null} if no handler could be found
     */
    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() + "'");
            }
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }

1.hm.getHandler(HttpServletRequest request)方法由AbstractHandlerMapping实现

/**
	 * 查找给定请求的handler,如果没有找到,回退到默认值
	 *
	 * @param request current HTTP request
	 * @return the corresponding handler instance, or the default handler
	 * @see #getHandlerInternal
	 */
	@Override
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		//获取request的处理程序Handler
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			//返回默认的Handler
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean名称或已解析的处理程序
		if (handler instanceof String) {
			//如果找到的handler是个bean名称
			String handlerName = (String) handler;
			handler = getApplicationContext().getBean(handlerName);
		}

		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		if (CorsUtils.isCorsRequest(request)) {
			//全局cors配置
			CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
		return executionChain;
	}

每个request请求都会对应到相关的请求处理bean或者处理方法getHandlerInternal(request)方法便是获取请求处理器的,可以参考https://blog.csdn.net/qq_23536449/article/details/99944430,然后对于每个request请求对应的处理器SpringMVC除了让我们可以在执行处理请求执行的前后添加相关的拦截器getHandlerExecutionChain(Object handler, HttpServletRequest request)

/**
	 * 为给定的处理程序构建{@link HandlerExecutionChain},包括
	 *   适用的拦截器。
	 * <p>默认实现使用给定的处理程序,处理程序映射的公共拦截器以及与当前请求URL
	 * 匹配的任何{@link MappedInterceptor}构建标准{@link HandlerExecutionChain}。
	 * 拦截器按其注册顺序添加。 子类可以覆盖它以扩展/重新排列拦截器列表。
	 * <p><b>注意:</ b>传入的处理程序对象可以是原始处理程序或预构建的{@link HandlerExecutionChain}。
	 * 这种方法应该明确地处理这两种情况,要么建立一个新的{@link HandlerExecutionChain},要么扩展现有的链。
	 * <p>要简单地在自定义子类中添加拦截器,请考虑调用{@code super.getHandlerExecutionChain(handler,request)}
	 * 并在返回的链对象上调用{@link HandlerExecutionChain#addInterceptor}。
	 * @param handler the resolved handler instance (never {@code null})
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain (never {@code null})
	 * @see #getAdaptedInterceptors()
	 */
	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		//handler可能为HandlerExecutionChain类型
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			//mappedInterceptor类型需要
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				//给定路径匹配成功
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

该方法将handler处理器封装为HandlerExecutionChain对象其中HandlerExecutionChain对象主要属性

public class HandlerExecutionChain {

	private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
	/**
	 * 处理器,处理请求
	 */
	private final Object handler;
	/**
	 * 拦截器
	 */
	private HandlerInterceptor[] interceptors;
}

handler用于执行请求处理的逻辑,interceptors用于在执行请求逻辑生命周期进行拦截操作。

2.当我们学习过https://blog.csdn.net/qq_23536449/article/details/99944430之后我们知道对于请求的处理要么是Spring帮我们找到一个继承AbstractController的bean处理请求比如通过BeanNameUrlHandlerMapping和SimpleUrlHandlerMapping,要么通过@RequestMapping注解定义对一个请求的处理,这时候请求的处理器是方法级别的,这种模式下Spring通过RequestMappingHandlerMapping帮我们实现对于请求处理方法(统一封装为HandlerMethod)的查找。所以Spring给我们提供了继承AbstractHandlerMapping的两个抽象类AbstractHandlerUrlMapping和AbstractHandlerMethodMapping类用于查找方法级别的请求处理对象和bean级别的请求处理器

3.AbstractHandlerUrlMapping.getHandlerInternal(HttpServletRequest request)

/**
	 * 查找给定请求的URL路径的处理程序。
	 * @param request current HTTP request
	 * @return the handler instance, or {@code null} if none found
	 */
	@Override
	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		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.
			Object rawHandler = null;
			//根处理器
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			//默认的处理器
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean name or resolved handler?
				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;
	}

/**
	 * 查找给定URL路径的处理程序实例。
	 * <p>支持直接匹配,例如 注册的“/ test”匹配“/ test”,
	 *   和各种Ant风格的模式匹配,例如 注册的“/ t *”匹配“/ test”和“/ team”。 有关详细信息,请参阅AntPathMatcher类。
	 * <p>寻找最精确的模式,其中最精确的定义为最长的路径模式。
	 * @param urlPath the URL the bean is mapped to
	 * @param request current HTTP request (to expose the path within the mapping to)
	 * @return the associated handler instance, or {@code null} if not found
	 * @see #exposePathWithinMapping
	 * @see org.springframework.util.AntPathMatcher
	 */
	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// Direct match?
		//通过url直接能查找到Handler
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}

		// Pattern match?
		// 使用pathMatcher查找Handler
		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 bestMatch = 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);
			}
			bestMatch = matchingPatterns.get(0);
		}
		if (bestMatch != null) {
			handler = this.handlerMap.get(bestMatch);
			if (handler == null) {
				if (bestMatch.endsWith("/")) {
					handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
				}
				if (handler == null) {
					throw new IllegalStateException(
							"Could not find handler for best pattern match [" + bestMatch + "]");
				}
			}
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, 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(bestMatch, 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, bestMatch, pathWithinMapping, uriTemplateVariables);
		}

		// No handler found...
		return null;
	}

方法内容比较多,忽略其他的复杂逻辑该方法,主要是从AbstractUrlHandlerMapping的handlerMap属性中获取request的url对应的处理器的bean谢谢。

对于handlerMap的初始化BeanNameUrlHandlerMapping和SimpleUrlHandlerMapping有所差异

SimpleUrlHandlerMapping通过它的registerHandlers(Map<String,Object> map)方法注册url对应的请求处理bean;


public void setUrlMap(Map<String, ?> urlMap) {
		this.urlMap.putAll(urlMap);
	}

@Override
	public void initApplicationContext() throws BeansException {
		super.initApplicationContext();
		registerHandlers(this.urlMap);
	}

/**
 * 注册URL映射中为相应路径指定的所有处理程序。
 * @param urlMap Map with URL paths as keys and handler beans or bean names as values
 * @throws BeansException if a handler couldn't be registered
 * @throws IllegalStateException if there is a conflicting handler registered
 */
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
   if (urlMap.isEmpty()) {
      logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
   }
   else {
      for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
         String url = entry.getKey();
         Object handler = entry.getValue();
         // Prepend with slash if not already present.
         if (!url.startsWith("/")) {
            url = "/" + url;
         }
         // Remove whitespace from handler bean name.
         if (handler instanceof String) {
            handler = ((String) handler).trim();
         }
         registerHandler(url, handler);
      }
   }
}

如果我们了解SimpleUrlHandlerMapping的用法,上面代码不难理解,读取配置的SimpleUrlHandlerMapping的map属性通过initApplicationContext()方法调用registerHandlers方法将配置的map属性的url对应的处理bean注册到AbstractHandlerMapping中的urlMap中。

BeanNameUrlHandlerMapping通过父类AbstractDetectingUrlHandlerMapping的detectHandlers();方法查找每个bean是否为请求处理对象通过beanName和aliasName是否以"/"开始判断。

/**
	 * 除了超类的初始化之外,还调用{@link #detectHandlers()}方法
	 */
	@Override
	public void initApplicationContext() throws ApplicationContextException {
		super.initApplicationContext();
		detectHandlers();
	}

/**
	 * 注册当前ApplicationContext中找到的所有处理程序。
	 * <p>处理程序的实际URL确定取决于具体情况
	 *   {@link #determineUrlsForHandler(String)}实现。 没有这样的URL可以确定的bean根本不被认为是处理程序。
	 * @throws org.springframework.beans.BeansException if the handler couldn't be registered
	 * @see #determineUrlsForHandler(String)
	 */
	protected void detectHandlers() throws BeansException {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
		}
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));
		for (String beanName : beanNames) {
			//查找给定beanName的所有url
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
				// URL paths found: Let's consider it a handler.
				registerHandler(urls, beanName);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
				}
			}
		}
	}

主要方法为determineUrlsForHandler(beanName);该方法委托给子类BeanNameUrlHandlerMapping实现

/**
	 * 检查URL的给定bean的名称和别名,以“/”开头。
	 */
	@Override
	protected String[] determineUrlsForHandler(String beanName) {
		List<String> urls = new ArrayList<String>();
		if (beanName.startsWith("/")) {
			urls.add(beanName);
		}
		//获取bean的别名
		String[] aliases = getApplicationContext().getAliases(beanName);
		for (String alias : aliases) {
			if (alias.startsWith("/")) {
				urls.add(alias);
			}
		}
		//获取给定beanName的所有urls
		return StringUtils.toStringArray(urls);
	}

大致逻辑就是对于每个bean都可能是潜在的处理器,如果beanName或者alias为以"/"开头的,则认为该bean为处理器,并且它处理的请求url为自身的beanName或者alias。

4.AbstractHandlerMethodMapping.getHandlerInternal(HttpServletRequest request)

/**
	 * 查找给定请求的处理程序方法。
	 */
	@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);
		}
		//加上读锁
		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();
		}
	}

/**
	 * 查找当前请求的最佳匹配处理程序方法。如果找到多个匹配项,则选择最佳匹配项。
	 * @param lookupPath mapping lookup path within the current servlet mapping
	 * @param request the current request
	 * @return the best-matching handler method, or {@code null} if no match
	 * @see #handleMatch(Object, String, HttpServletRequest)
	 * @see #handleNoMatch(Set, String, HttpServletRequest)
	 */
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<Match>();
		//获取到了@RequestMapping注解产生的RequestMappingInfo数据
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		//如果不为null
		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));
			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 + "}");
				}
			}
			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);
		}
	}

查找的中心主要是围绕着AbstractHandlerMethodMapping对象的MappingRegistry属性查找。

关于MappingRegistry的初始化逻辑主要如下

/**
	 * Detects handler methods at initialization.
	 */
	@Override
	public void afterPropertiesSet() {
		initHandlerMethods();
	}

	/**
	 * 在ApplicationContext中扫描bean,检测并注册处理程序方法。
	 * @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) {
			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);
					}
				}
				//对应class类有@Controller或者@RequestMapping注解
				if (beanType != null && isHandler(beanType)) {
					detectHandlerMethods(beanName);
				}
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

	/**
	 * 在处理程序中查找处理程序方法。
	 * @param handler the bean name of a handler or a handler instance
	 */
	protected void detectHandlerMethods(final Object handler) {
		//处理器的类型如果是String类型,把该bean创建起来
		Class<?> handlerType = (handler instanceof String ?
				getApplicationContext().getType((String) handler) : handler.getClass());
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
		//查找userType每个method方法上的@RequestMapping并映射成为{@link RequestMappingInfo}
		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);
		}
		//遍历每个methods
		for (Map.Entry<Method, T> entry : methods.entrySet()) {
			Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
			//方法上用于映射请求处理的的元数据
			T mapping = entry.getValue();
			registerHandlerMethod(handler, invocableMethod, mapping);
		}
	}

	/**
	 * 注册处理程序方法及其唯一映射。 在启动时为每个检测到的处理程序方法调用。
	 * @param handler the bean name of the handler or the handler instance
	 * @param method the method to register
	 * @param mapping the mapping conditions associated with the handler method
	 * @throws IllegalStateException if another method was already registered
	 * under the same mapping
	 */
	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		this.mappingRegistry.register(mapping, handler, method);
	}

大致逻辑主要为获取所有beanNames,然后过滤真正的请求处理bean(bean包含@Controller或者@RequestMapping)注解的beanName,然后解析这些beanName所有的方法并将那些有@RequestMapping注解的方法连同beanName对应的bean和@RequestMapping注解的元数据封装起来,注册到MappingRegistry。

class MappingRegistry {

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

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

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

		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();
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值