【Spring MVC源码解析】(三)HandlerMapping

HandlerMapping家族成员可以分为两支,一支继承自AbastractUrlHandlerMapping,另一支继承自AbastracHandlerMethodMapping,两只都继承自AbastractHandlerMapping。

类图

绿框 AbstractHandlerMapping 抽象类,实现了【获得请求对应的处理器和拦截器们】的骨架逻辑,然后提供 getHandlerInternal(HttpServletRequest request)模板方法,交由子类实现。

AbstractHandlerMapping 的子类:

红框 AbstractUrlHandlerMapping 系,基于 URL 进行匹配。当然,实际我们开发时,这种方式已经基本不用了,被 @RequestMapping 等注解的方式所取代。不过,Spring MVC 内置的一些路径匹配,还是使用这种方式。

黄框 AbstractHandlerMethodMapping 系,基于 Method 进行匹配。例如,我们所熟知的 @RequestMapping 等注解的方式。

白框 MatchableHandlerMapping 接口,定义判断请求和指定 pattern 路径是否匹配的接口方法。

AbstractHandlerMapping

 AbstractHandlerMapping采用模板模式设计了HandlerMapping的整体结构,然后子类通过实现模板方法提供一些初始值和具体算法即可。AbstractHandlerMapping继承了WebApplicationObjectSupport,初始化时会调用模板方法initApplicationContext,即AbstractHandlerMapping的创建就是在initApplicationContext中实现。

// AbstractHandlerMapping.java

@Override
protected void initApplicationContext() throws BeansException {
    // 空方法。交给子类实现,用于注册自定义的拦截器到 interceptors 中。目前暂无子类实现。
    extendInterceptors(this.interceptors);
    // 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中
    detectMappedInterceptors(this.adaptedInterceptors);
    // 将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中
    initInterceptors();
}

detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) 方法,扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中。代码如下:

// AbstractHandlerMapping.java

protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
	// 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中
	// MappedInterceptor 会根据请求路径做匹配,是否进行拦截。
	mappedInterceptors.addAll(
			BeanFactoryUtils.beansOfTypeIncludingAncestors(
					obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}

initInterceptors() 方法,将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中。代码如下:

// AbstractHandlerMapping.java

protected void initInterceptors() {
    if (!this.interceptors.isEmpty()) {
        // 遍历 interceptors 数组
        for (int i = 0; i < this.interceptors.size(); i++) {
            // 获得 interceptor 对象
            Object interceptor = this.interceptors.get(i);
            if (interceptor == null) { // 若为空,抛出 IllegalArgumentException 异常
                throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
            }
            // 将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中
            // 注意,HandlerInterceptor 无需进行路径匹配,直接拦截全部
            this.adaptedInterceptors.add(adaptInterceptor(interceptor)); // <x>
        }
    }
}

可以看到AbstractHandlerMapping保存了所有Interceptor,其属性有两个List类型的Interceptor

/**
 * 配置的拦截器数组,并不会直接使用
 *
 * 而是在 {@link #initInterceptors()} 方法中,初始化到 {@link #adaptedInterceptors} 中使用
 *
 * 添加方式有两种:
 *
 * 1. {@link #setInterceptors(Object...)} 方法
 * 2. {@link #extendInterceptors(List)} 方法
 */
private final List<Object> interceptors = new ArrayList<>();

/**
 * 初始化后的拦截器 HandlerInterceptor 数组,使用时与Url匹配
 */
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();

初始化完成后,我们来看如何获取Handler和Interceptor。getHandler(HttpServletRequest request) 方法,获得请求对应的 HandlerExecutionChain 对象。代码如下:

// DispatcherServlet.java

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        // 遍历 HandlerMapping 数组
        for (HandlerMapping mapping : this.handlerMappings) {
            // 获得请求对应的 HandlerExecutionChain 对象
            HandlerExecutionChain handler = mapping.getHandler(request);
            // 获得到,则返回
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}
// AbstractHandlerMapping.java

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // <1> 获得处理器。该方法是抽象方法,由子类实现
    Object handler = getHandlerInternal(request);
    // <2> 获得不到,则使用默认处理器
    if (handler == null) {
        handler = getDefaultHandler();
    }
    // <3> 还是获得不到,则返回 null
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    // <4> 如果找到的处理器是 String 类型,则从容器中找到 String 对应的 Bean 类型作为处理器。
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    // <5> 获得 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 (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    // <7> 返回    
    return executionChain;
}

getHandlerExecutionChain(Object handler, HttpServletRequest request) 方法,获得 HandlerExecutionChain 对象。代码如下:

// AbstractHandlerMapping.java

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    // 创建 HandlerExecutionChain 对象
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    // 获得请求路径
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    // 遍历 adaptedInterceptors 数组,获得请求匹配的拦截器
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        // 需要匹配,若路径匹配,则添加到 chain 中
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { // 匹配
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        // 无需匹配,直接添加到 chain 中
        } else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

AbstractHandlerMethodMapping

AbstractHandlerMethodMapping ,实现 InitializingBean 接口,继承 AbstractHandlerMapping 抽象类,以 Method 作为 Handler 的 HandlerMapping 抽象类,提供 Mapping 的初始化、注册等通用的骨架方法。这就是我们常说的模板方法模式。

// AbstractHandlerMethodMapping.java

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {

    /**
     * Mapping 注册表
     */
    private final MappingRegistry mappingRegistry = new MappingRegistry();

    /**
     * Mapping 命名策略
     */
    @Nullable
    private HandlerMethodMappingNamingStrategy<T> namingStrategy;
}

泛型T代表匹配Handler的条件而专门使用的一种类,这里的条件就不只是url,还包含如Request类型(get、post),请求参数、Head等都可以作为匹配Handler的条件。默认是用RequestMappingInfo。

MappingRegistry ,是 AbstractHandlerMethodMapping 的私有类,Mapping 注册表。

// AbstractHandlerMethodMapping.java#MappingRegistry

/**
 * 注册表
 *
 * KEY: MappingInfo
 */
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();

/**
 * 注册表 保存着匹配条件(RequestCondition)和HandlerMethod的对应关系
 *
 * KEY:MappingInfo
 */
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();

/**
 * 直接 URL 的映射,保存着Url与匹配条件(RequestCondition)对应关系
 *
 * KEY:直接 URL
 * VALUE:MappingInfo 数组
 */
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();

/**
 * MappingInfo 的名字与 HandlerMethod 的映射
 *
 * KEY:Mapping 的名字
 * VALUE:HandlerMethod 数组
 */
private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();

/**
 * cors
 */
private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();

/**
 * 读写锁
 */
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

初始化

了解一些关键属性后,我们来看它的初始化,AbstractHandlerMapping 实现 InitializingBean接口,spring容器调用其afterPropertiesSet()方法进行初始化。

// AbstractHandlerMethodMapping.java

/**
 * 是否只扫描可访问的 HandlerMethod 们
 */
private boolean detectHandlerMethodsInAncestorContexts = false;

@Override
public void afterPropertiesSet() {
	// <x> 初始化处理器的方法们
	initHandlerMethods();
}

/**
 * Scan beans in the ApplicationContext, detect and register handler methods.
 * @see #getCandidateBeanNames()
 * @see #processCandidateBean
 * @see #handlerMethodsInitialized
 */
protected void initHandlerMethods() {
	//遍历 Bean ,逐个处理
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			// <1.2> 处理 Bean
			processCandidateBean(beanName);
		}
	}
	//初始化处理器的方法们。目前是空方法,暂无具体的实现
	handlerMethodsInitialized(getHandlerMethods());
}

getCandidateBeanNames() 方法,获得所有 Bean 的名字们,然后进行遍历处理。

// AbstractHandlerMethodMapping.java

/**
 * Determine the names of candidate beans in the application context.
 * @since 5.1
 * @see #setDetectHandlerMethodsInAncestorContexts
 * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors
 */
protected String[] getCandidateBeanNames() {
	return (this.detectHandlerMethodsInAncestorContexts ? // 可访问
			BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
			obtainApplicationContext().getBeanNamesForType(Object.class));
}

processCandidateBean(String beanName) 方法,判断 Bean 是否为处理器,如果是,则扫描处理器方法。代码如下:

// AbstractHandlerMethodMapping.java

/**
 * Determine the type of the specified candidate bean and call
 * {@link #detectHandlerMethods} if identified as a handler type.
 * <p>This implementation avoids bean creation through checking
 * {@link org.springframework.beans.factory.BeanFactory#getType}
 * and calling {@link #detectHandlerMethods} with the bean name.
 * @param beanName the name of the candidate bean
 * @since 5.1
 * @see #isHandler
 * @see #detectHandlerMethods
 */
protected void processCandidateBean(String beanName) {
    // <1> 获得 Bean 对应的类型
    Class<?> beanType = null;
    try {
        beanType = obtainApplicationContext().getType(beanName);
    } catch (Throwable ex) {
        // An unresolvable bean type, probably from a lazy bean - let's ignore it.
        if (logger.isTraceEnabled()) {
            logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
        }
    }
    // 判断 Bean 是否为处理器,如果是,则扫描处理器方法
    if (beanType != null && isHandler(beanType)) { // <2.1>
        detectHandlerMethods(beanName); // <2.2>
    }
}

调用 #isHandler(Class<?> beanType) 抽象方法,判断 Bean 的类型是否为处理器,具体实现在RequestMappingHandlerMapping

@Override
protected boolean isHandler(Class<?> beanType) {
        //判断类上@Controller注解,或方法上RequestMapping注解
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

detectHandlerMethods初始化处理器的方法们。代码如下:

// AbstractHandlerMethodMapping.java

/**
 * Look for handler methods in a handler.
 * @param handler the bean name of a handler or a handler instance
 */
protected void detectHandlerMethods(final Object handler) {
    // <1> 获得处理器类型
    Class<?> handlerType = (handler instanceof String ?
            obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
        // <2> 获得真实的类。因为,handlerType 可能是代理类
        final Class<?> userType = ClassUtils.getUserClass(handlerType);
        // <3> 获得匹配的方法的集合
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                (MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType)); // 抽象方法,子类实现
        if (logger.isTraceEnabled()) {
            logger.trace("Mapped " + methods.size() + " handler method(s) for " + userType + ": " + methods);
        }
        // <4> 遍历方法,逐个注册 HandlerMethod
        methods.forEach((key, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(key, userType);
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

#getMappingForMethod(Method method, Class<?> handlerType) 方法,获得方法上的 RequestMappingInfo 对象,基于 @RequestMapping 构造。代码如下:

// RequestMappingHandlerMapping.java

/**
 * 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
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // <1> 基于方法上的 @RequestMapping 注解,创建 RequestMappingInfo 对象
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        // <2> 基于类上的 @RequestMapping 注解,合并进去
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
            info = typeInfo.combine(info);
        }
        // <3> 如果有前缀,则设置到 info 中
        String prefix = getPathPrefix(handlerType);
        if (prefix != null) {
            info = RequestMappingInfo.paths(prefix).build().combine(info);
        }
    }
    return info;
}

#registerHandlerMethod(Object handler, Method method, T mapping) 方法,注册 HandlerMethod

// AbstractHandlerMethodMapping.java

/**
 * 注册 HandlerMethod
 *
 * Register a handler method and its unique mapping. Invoked at startup for
 * each detected handler method.
 * @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);
}

// AbstractHandlerMethodMapping.java#MappingRegistry

public void register(T mapping, Object handler, Method method) {
    // <1> 获得写锁
    this.readWriteLock.writeLock().lock();
    try {
        // <2.1> 创建 HandlerMethod 对象
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        // <2.2> 校验当前 mapping 不存在,否则抛出 IllegalStateException 异常
        assertUniqueMethodMapping(handlerMethod, mapping);
        // <2.3> 添加 mapping + HandlerMethod 到 mappingLookup 中
        this.mappingLookup.put(mapping, handlerMethod);

        // <3.1> 获得 mapping 对应的普通 URL 数组
        List<String> directUrls = getDirectUrls(mapping);
        // <3.2> 添加到 url + mapping 到 urlLookup 集合中
        for (String url : directUrls) {
            this.urlLookup.add(url, mapping);
        }

        // <4> 初始化 nameLookup
        String name = null;
        if (getNamingStrategy() != null) {
            // <4.1> 获得 Mapping 的名字
            name = getNamingStrategy().getName(handlerMethod, mapping);
            // <4.2> 添加到 mapping 的名字 + HandlerMethod 到 nameLookup 中
            addMappingName(name, handlerMethod);
        }

        // <5> TODO 1012 cors
        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }

        // <6> 创建 MappingRegistration 对象,并 mapping + MappingRegistration 添加到 registry 中
        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod));
    } finally {
        // <7> 释放写锁
        this.readWriteLock.writeLock().unlock();
    }
}

使用

getHandlerInternal(ServerWebExchange exchange) 方法,获得请求对应的 HandlerMethod 对象。代码如下:

// AbstractHandlerMethodMapping.java

/**
 * Look up a handler method for the given request.
 */
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 获得请求的路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    // 获得读锁
    this.mappingRegistry.acquireReadLock();
    try {
        //  获得 HandlerMethod 对象
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        // 进一步,获得 HandlerMethod 对象
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    } finally {
        // 释放读锁
        this.mappingRegistry.releaseReadLock();
    }
}

调用 #lookupHandlerMethod(ServerWebExchange exchange) 方法,获得 HandlerMethod 对象。

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    // <1> 存储匹配上当前请求的结果
    List<Match> matches = new ArrayList<>();
    // <1.1> 优先,基于直接 URL 的 Mapping 们,进行匹配
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        addMatchingMappings(directPathMatches, matches, request);
    }
    // <1.2> 如果不能直接使用looupPath得到匹配条件,扫描所有注册表的 Mapping 们,进行匹配
    if (matches.isEmpty()) {
        // No choice but to go through all mappings...
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    // <2> 如果匹配到,则获取最佳匹配的 Match 对象的 handlerMethod 属性
    if (!matches.isEmpty()) {
        // <2.1> 创建 MatchComparator 对象,排序 matches 结果
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
        matches.sort(comparator);
        // <2.2> 获得首个 Match 对象
        Match bestMatch = matches.get(0);
        // <2.3> 处理存在多个 Match 对象的情况!!
        if (matches.size() > 1) {
            if (logger.isTraceEnabled()) {
                logger.trace(matches.size() + " matching mappings: " + matches);
            }
            
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            // 比较 bestMatch 和 secondBestMatch ,如果相等,说明有问题,抛出 IllegalStateException 异常
            // 因为,两个优先级一样高,说明无法判断谁更优先
            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 + "}");
            }
        }
        // <2.4> 处理首个 Match 对象
        handleMatch(bestMatch.mapping, lookupPath, request);
        // <2.5> 返回首个 Match 对象的 handlerMethod 属性
        return bestMatch.handlerMethod;
    // <3> 如果匹配不到,则处理不匹配的情况
    } else {
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

整个过程中使用Match作为载体,Match是个内部类,封装了匹配条件和HandlerMothd两个属性。

addMatchingMappings(Collection<T> mappings, List<Match> matches, ServerWebExchange exchange) 方法,将当前请求和注册表中的 Mapping 进行匹配。若匹配成功,则生成 Mapping 记录,添加到 matches 中。代码如下:

// AbstractHandlerMethodMapping.java

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, ServerWebExchange exchange) {
    // 遍历 Mapping 数组
	for (T mapping : mappings) {
	    // <1> 执行匹配
		T match = getMatchingMapping(mapping, exchange);
		// <2> 如果匹配,则创建 Match 对象,添加到 matches 中
		if (match != null) {
			matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
		}
	}
}

其中getMatchingMapping(T mapping, HttpServletRequest request),由子类RequestMappingInfoHandlerMapping实现

@Override
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
		return info.getMatchingCondition(request);
}

RequestMappingInfo

// RequestMappingInfo.java

/**
 * 名字
 */
@Nullable
private final String name;

/**
 * 请求路径的条件
 */
private final PatternsRequestCondition patternsCondition;

/**
 * 请求方法的条件
 */
private final RequestMethodsRequestCondition methodsCondition;

/**
 * 参数的条件
 */
private final ParamsRequestCondition paramsCondition;

/**
 * 请求头的条件
 */
private final HeadersRequestCondition headersCondition;

/**
 * 可消费的 Content-Type 的条件
 */
private final ConsumesRequestCondition consumesCondition;

/**
 * 可生产的 Content-Type 的条件
 */
private final ProducesRequestCondition producesCondition;

/**
 * 自定义的条件
 */
private final RequestConditionHolder customConditionHolder;

#getMatchingCondition(HttpServletRequest request) 方法,从当前 RequestMappingInfo 获得匹配的条件。如果匹配,则基于其匹配的条件,创建新的 RequestMappingInfo 对象。如果不匹配,则返回 null 。代码如下:

@SuppressWarnings("Duplicates")
@Override
@Nullable
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
    // 匹配 methodsCondition、paramsCondition、headersCondition、consumesCondition、producesCondition
	RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
	ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
	HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
	ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
	ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
	// 如果任一为空,则返回 null ,表示匹配失败
	if (methods == null || params == null || headers == null || consumes == null || produces == null) {
		return null;
	}

	// 匹配 patternsCondition
	PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
	if (patterns == null) { // 如果 patterns 为空,则返回 null ,表示匹配失败
		return null;
	}

	// 匹配 customConditionHolder
	RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
	if (custom == null) { // 如果 custom 为空,则返回 null ,表示匹配失败
		return null;
	}

	// 创建匹配的 RequestMappingInfo 对象。
	// 为什么要创建 RequestMappingInfo 对象呢?因为当前 RequestMappingInfo 对象,一个 methodsCondition 可以配置 GET、POST、DELETE 等等条件,但是实际就匹配一个请求类型,此时 methods 只代表其匹配的那个。
	return new RequestMappingInfo(this.name, patterns,
			methods, params, headers, consumes, produces, custom.getCondition());
}

#compareTo(RequestMappingInfo other, HttpServletRequest request) 方法,比较优先级。代码如下:

// RequestMappingInfo.java

/**
 * Compares "this" info (i.e. the current instance) with another info in the context of a request.
 * <p>Note: It is assumed both instances have been obtained via
 * {@link #getMatchingCondition(HttpServletRequest)} to ensure they have conditions with
 * content relevant to current request.
 */
@Override
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
	int result;
	// Automatic vs explicit HTTP HEAD mapping
	// 针对 HEAD 请求方法,特殊处理
	if (HttpMethod.HEAD.matches(request.getMethod())) {
		result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
		if (result != 0) {
			return result;
		}
	}
	// 比较 patternsCondition
	result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
	if (result != 0) {
		return result;
	}
	// 比较 paramsCondition
	result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
	if (result != 0) {
		return result;
	}
	// 比较 headersCondition
	result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
	if (result != 0) {
		return result;
	}
	// 比较 consumesCondition
	result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
	if (result != 0) {
		return result;
	}
	// 比较 producesCondition
	result = this.producesCondition.compareTo(other.getProducesCondition(), request);
	if (result != 0) {
		return result;
	}
	// Implicit (no method) vs explicit HTTP method mappings
	// 比较 methodsCondition
	result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
	if (result != 0) {
		return result;
	}
	// 比较 customConditionHolder
	result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
	if (result != 0) {
		return result;
	}
	return 0;
}

虽然代码非常长,实际都是按照优先级,逐个调用每个属性对应的 #compareTo(RequestMethodsRequestCondition other, HttpServletRequest request) 方法,直到比到不相等

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wonder ZH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值