HandlerMapping之RequestMappingHandlerMapping获取Handler
一、HandlerMapping类图
二、根据请求获取 HandlerExecutionChain
2.1 获取HandlerMethod流程
(1) 根据请求URL获取直接匹配的List<RequestMappingInfo>作为候选,如果没有则取所有的RequestMappingInfo作为候选,遍历候选的RequestMappingInfo,调用RequestMappingInfo#
getMatchingCondition方法(返回不为NULL则匹配),获取匹配的List<RequestMappingInfo>。可以扩展实现自定义匹配规则,传送门:2.1.3
(2) 如果没有匹配的RequestMappingInfo,按照具体不匹配原因抛出对应异常,比如:请求方法不匹配、请求参数类型不匹配、响应类型不匹配、方法参数缺失等
(3) 如果有多个匹配的RequestMappingInfo,OPTION请求则会直接返回,否则找出最匹配的RequestMappingInfo,如果有多个匹配度相同的RequestMappingInfo则抛出异常。
2.2 AbstractHandlerMapping
2.2.1 获取请求对应的HandlerExecutionChain getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 查找给定请求的Handler,如果未找到特定Handler,则返回{@code null}。如果返回{@code null}值,则使用默认Handler。留给子类实现,传送门:3.3.1
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// handler和interceptor(匹配的MappedInterceptor)封装为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);
// 匹配请求的跨域配置:如果handler是CorsConfigurationSource,获取request的跨域配置
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
// 全剧跨域配置 + 匹配请求的跨域配置
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
2.2.2 封装Handler和请求对应的拦截器链 getHandlerExecutionChain
// handler和interceptor(匹配的MappedInterceptor)封装为HandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
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;
}
2.2.3 获取请求对应的跨域配置 getCorsConfiguration
// 如果handler是CorsConfigurationSource,获取request的跨域配置
protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
Object resolvedHandler = handler;
if (handler instanceof HandlerExecutionChain) {
resolvedHandler = ((HandlerExecutionChain) handler).getHandler();
}
if (resolvedHandler instanceof CorsConfigurationSource) {
return ((CorsConfigurationSource) resolvedHandler).getCorsConfiguration(request);
}
return null;
}
2.2.4 生成带跨域配置的HandlerExecutionChain getCorsHandlerExecutionChain
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
if (CorsUtils.isPreFlightRequest(request)) {
HandlerInterceptor[] interceptors = chain.getInterceptors();
chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
}
else {
chain.addInterceptor(new CorsInterceptor(config));
}
return chain;
}
2.3 AbstractHandlerMethodMapping
2.3.1 获取请求对应的HandlerMethod getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// this.mappingRegistry初始化时注册RequestMappingInfo 传送门:2.1.2.6、2.1.2.7
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
2.3.2 查找匹配请求的HandlerMethod lookupHandlerMethod
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
// Match封装了HandlerMethod和RequestMappingInfo
List<Match> matches = new ArrayList<>();
// 根据请求URL获取直接匹配的List<RequestMappingInfo>
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// 获取匹配请求的处理方法:调用RequestMappingInfo#getMatchingCondition返回不为NULL则匹配
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// 除了浏览所有mappings外别无选择。this.mappingRegistry.getMappings().keySet()获取所有的RequestMappingInfo,遍历找到匹配的处理方法
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
// 由子类实现,getMappingComparator 获取RequestMappingInfo比较器
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);
}
// OPTION请求直接返回
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);
// 由子类实现:在请求中公开URI模板变量,矩阵变量和可生产的媒体类型,在请求中保存了一些属性
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
2.3.3 获取匹配请求的HandlerMethod addMatchingMappings
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
// 由子类实现,检查给定的RequestMappingInfo是否与当前请求匹配,调用RequestMappingInfo#getMatchingCondition
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
2.4 RequestMappingInfoHandlerMapping
2.4.1 检查给定的RequestMappingInfo是否与当前请求匹配 getMatchingMapping
// 检查给定的RequestMappingInfo是否与当前请求匹配,并返回一个(可能是新的)实例,该实例具有与当前请求匹配的条件-例如带有URL模式的子集。
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
return info.getMatchingCondition(request);
}
2.4.2 匹配当前请求设置属性 handleMatch
// 在请求中公开URI模板变量,矩阵变量和可生产的媒体类型
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
super.handleMatch(info, lookupPath, request);
String bestPattern;
Map<String, String> uriVariables;
Set<String> patterns = info.getPatternsCondition().getPatterns();
if (patterns.isEmpty()) {
bestPattern = lookupPath;
uriVariables = Collections.emptyMap();
}
else {
bestPattern = patterns.iterator().next();
uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
}
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
if (isMatrixVariableContentAvailable()) {
Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);
request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);
}
Map<String, String> decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);
if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
}
}
2.4.3 针对不匹配请求返回具体异常 handleNoMatch
protected HandlerMethod handleNoMatch(
Set<RequestMappingInfo> infos, String lookupPath, HttpServletRequest request) throws ServletException {
PartialMatchHelper helper = new PartialMatchHelper(infos, request);
if (helper.isEmpty()) {
return null;
}
if (helper.hasMethodsMismatch()) {
Set<String> methods = helper.getAllowedMethods();
if (HttpMethod.OPTIONS.matches(request.getMethod())) {
HttpOptionsHandler handler = new HttpOptionsHandler(methods);
return new HandlerMethod(handler, HTTP_OPTIONS_HANDLE_METHOD);
}
// 请求处理程序不支持特定请求方法时引发的异常
throw new HttpRequestMethodNotSupportedException(request.getMethod(), methods);
}
if (helper.hasConsumesMismatch()) {
Set<MediaType> mediaTypes = helper.getConsumableMediaTypes();
MediaType contentType = null;
if (StringUtils.hasLength(request.getContentType())) {
try {
contentType = MediaType.parseMediaType(request.getContentType());
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
}
// 当客户端POST,PUT或PATCH的内容不受请求处理程序支持时,抛出此异常
throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<>(mediaTypes));
}
if (helper.hasProducesMismatch()) {
Set<MediaType> mediaTypes = helper.getProducibleMediaTypes();
// 当请求处理程序无法生成客户端可接受的响应时引发的异常
throw new HttpMediaTypeNotAcceptableException(new ArrayList<>(mediaTypes));
}
if (helper.hasParamsMismatch()) {
List<String[]> conditions = helper.getParamConditions();
// {@link ServletRequestBindingException}子类,指示不满意的参数条件,通常使用{@code @Controller}类型级别的{@code @RequestMapping} 注释表示。
throw new UnsatisfiedServletRequestParameterException(conditions, request.getParameterMap());
}
return null;
}
三、RequestMappingInfo
3.1 检查给定的RequestMappingInfo是否与当前请求匹配 getMatchingCondition
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
if (methods == null) {
return null;
}
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
if (params == null) {
return null;
}
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
if (headers == null) {
return null;
}
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
if (consumes == null) {
return null;
}
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
if (produces == null) {
return null;
}
PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
if (patterns == null) {
return null;
}
// 自定义匹配规则 传送门:2.2.3
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
if (custom == null) {
return null;
}
return new RequestMappingInfo(this.name, patterns,
methods, params, headers, consumes, produces, custom.getCondition());
}