SpringMVC源码-getHandler
DispatcherServlet.getHandler(HttpServletRequest request)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.hanlookupHandlerMethoddlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
如果handlerMappings不为null,从handlerMappings中找出处理当前请求的HandlerExecutionChain并返回。handlerMappings集合的元素分别是RequestMappingHandlerMapping,BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping。
一、RequestMappingHandlerMapping
AbstractHandlerMapping.getHandler(HttpServletRequest request)
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
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 = obtainApplicationContext().getBean(handlerName);
}
// Ensure presence of cached lookupPath for interceptors and others
if (!ServletRequestPathUtils.hasCachedPath(request)) {
initLookupPath(request);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = getCorsConfiguration(handler, request);
if (getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
config = (globalConfig != null ? globalConfig.combine(config) : config);
}
if (config != null) {
config.validateAllowCredentials();
}
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
1、getHandlerInternal获取handle,如果handle为null则getDefaultHandler获取默认handle,handle还为null返回。
2、如果handle是String,handle可能为beanName,调用getBean获取bean
3、如果拦截器没有缓存查找路径就initLookupPath解析拦截器路径并缓存。
4、获取HandlerExecutionChain
5、如果有CORS配置则处理CORS
RequestMappingInfoHandlerMapping.getHandlerInternal(HttpServletRequest request)
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
try {
return super.getHandlerInternal(request);
}
finally {
ProducesRequestCondition.clearMediaTypesAttribute(request);
}
}
AbstractHandlerMethodMapping.getHandlerInternal(HttpServletRequest request)
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
1、initLookupPath查找request请求路径
2、lookupHandlerMethod查找请求路径处理方法HandlerMethod
3、如果HandlerMethod不为null则handlerMethod.createWithResolvedBean解析处理方法对应的bean。
AbstractHandlerMethodMapping.initLookupPath(HttpServletRequest request)
protected String initLookupPath(HttpServletRequest request) {
if (usesPathPatterns()) {
request.removeAttribute(UrlPathHelper.PATH_ATTRIBUTE);
RequestPath requestPath = ServletRequestPathUtils.getParsedRequestPath(request);
String lookupPath = requestPath.pathWithinApplication().value();
return UrlPathHelper.defaultInstance.removeSemicolonContent(lookupPath);
}
else {
return getUrlPathHelper().resolveAndCacheLookupPath(request);
}
}
1、如果usesPathPatterns()为true,调用ServletRequestPathUtils.getParsedRequestPath解析lookupPath。usesPathPatterns()默认为false。
2、调用getUrlPathHelper().resolveAndCacheLookupPath解析lookupPath
UrlPathHelper.resolveAndCacheLookupPath(HttpServletRequest request)
public String resolveAndCacheLookupPath(HttpServletRequest request) {
String lookupPath = getLookupPathForRequest(request);
request.setAttribute(PATH_ATTRIBUTE, lookupPath);
return lookupPath;
}
1、getLookupPathForRequest解析request对应的请求路径
2、PATH_ATTRIBUTE为key,请求路径lookupPath为value设置属性到request中
UrlPathHelper.getLookupPathForRequest(HttpServletRequest request)
public String getLookupPathForRequest(HttpServletRequest request) {
String pathWithinApp = getPathWithinApplication(request);
// Always use full path within current servlet context?
if (this.alwaysUseFullPath || skipServletPathDetermination(request)) {
return pathWithinApp;
}
// Else, use path within current servlet mapping if applicable
String rest = getPathWithinServletMapping(request, pathWithinApp);
if (StringUtils.hasLength(rest)) {
return rest;
}
else {
return pathWithinApp;
}
}
1、getPathWithinApplication从request中返回请求路径
2、如果使用全路径或skipServletPathDetermination为true则返回,skipServletPathDetermination检查是否可跳过请求路径
3、getPathWithinServletMapping使用当前Servlet中映射的路径
UrlPathHelper.getPathWithinApplication(HttpServletRequest request)
public String getPathWithinApplication(HttpServletRequest request) {
String contextPath = getContextPath(request);
String requestUri = getRequestUri(request);
String path = getRemainingPath(requestUri, contextPath, true);
if (path != null) {
// Normal case: URI contains context path.
return (StringUtils.hasText(path) ? path : "/");
}
else {
return requestUri;
}
}
1、getContextPath从request获取contextPath
2、getRequestUri从request获取requestUri
3、getRemainingPath从requestUri中去掉contextPath剩余部分,如requestUri为/myself-web/userParam0,contextPath为/myself-web,getRemainingPath(requestUri, contextPath, true)结果为/userParam0
UrlPathHelper.getContextPath(HttpServletRequest request)
public String getContextPath(HttpServletRequest request) {
String contextPath = (String) request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE);
if (contextPath == null) {
contextPath = request.getContextPath();
}
if (StringUtils.matchesCharacter(contextPath, '/')) {
// Invalid case, but happens for includes on Jetty: silently adapt it.
contextPath = "";
}
return decodeRequestString(request, contextPath);
}
1、从request中获取INCLUDE_CONTEXT_PATH_ATTRIBUTE属性,如果为null则从request中获取contextPath
2、decodeRequestString解码contextPath
UrlPathHelper.getRequestUri(HttpServletRequest request)
public String getRequestUri(HttpServletRequest request) {
String uri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE);
if (uri == null) {
uri = request.getRequestURI();
}
return decodeAndCleanUriString(request, uri);
}
1、从request中获取INCLUDE_REQUEST_URI_ATTRIBUTE属性,如果为null则从request中获取RequestURI
2、decodeAndCleanUriString解码RequestURI
UrlPathHelper.skipServletPathDetermination(HttpServletRequest request)
private boolean skipServletPathDetermination(HttpServletRequest request) {
if (servlet4Present) {
return Servlet4Delegate.skipServletPathDetermination(request);
}
return false;
}
如果servlet4Present为true,调用Servlet4Delegate.skipServletPathDetermination检查是否可跳过请求路径,否则返回false。
Servlet4Delegate.skipServletPathDetermination(HttpServletRequest request)
public static boolean skipServletPathDetermination(HttpServletRequest request) {
HttpServletMapping mapping = (HttpServletMapping) request.getAttribute(RequestDispatcher.INCLUDE_MAPPING);
if (mapping == null) {
mapping = request.getHttpServletMapping();
}
MappingMatch match = mapping.getMappingMatch();
return (match != null && (!match.equals(MappingMatch.PATH) || mapping.getPattern().equals("/*")));
}
获取MappingMatch,判断MappingMatch是否匹配MappingMatch.PATH(MappingMatch.PATH是/faces/这种的映射路径)和HttpServletMapping获取pattern是否和/相等。
AbstractHandlerMethodMapping.lookupHandlerMethod(String lookupPath, HttpServletRequest request)
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
for (Match match : matches) {
if (match.hasCorsConfig()) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
}
}
else {
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.getHandlerMethod().getMethod();
Method m2 = secondBestMatch.getHandlerMethod().getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
else {
return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
}
1、mappingRegistry.getMappingsByDirectPath通过请求路径获取RequestMappingInfo集合,mappingRegistry.getMappingsByDirectPath只能获取请求路径中不存在模式的路径,即路径中不存在*,{}.
2、如果请求路径中不存在模式,调用addMatchingMappings添加Match集合
3、如果matches为空,即请求路径存在模式,调用addMatchingMappings从mappingRegistry.getRegistrations().keySet()(包含所有请求方法处理的RequestMappingInfo集合)中添加Match匹配request的集合
4、如果matches集合非空,查找最匹配的Match,调用handleMatch处理Match。handleMatch在请求中公开URI模板变量、矩阵变量和可生产的媒体类型。如果matches集合为空,handleNoMatch处理没有Match的情况。
AbstractHandlerMethodMapping.addMatchingMappings(Collection
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
}
}
}
遍历mappings集合,即封装了@Controller类中@RequestMapping标注的方法集合,getMatchingMapping返回匹配请求的RequestMappingInfo加到Match集合中。
RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfo info, HttpServletRequest request)
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
return info.getMatchingCondition(request);
}
返回匹配请求的RequestMappingInfo。
RequestMappingInfo.getMatchingCondition(HttpServletRequest request)
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;
}
PathPatternsRequestCondition pathPatterns = null;
if (this.pathPatternsCondition != null) {
pathPatterns = this.pathPatternsCondition.getMatchingCondition(request);
if (pathPatterns == null) {
return null;
}
}
PatternsRequestCondition patterns = null;
if (this.patternsCondition != null) {
patterns = this.patternsCondition.getMatchingCondition(request);
if (patterns == null) {
return null;
}
}
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
if (custom == null) {
return null;
}
return new RequestMappingInfo(this.name, pathPatterns, patterns,
methods, params, headers, consumes, produces, custom, this.options);
}
依次调用methodsCondition,paramsCondition,headersCondition,consumesCondition,producesCondition,pathPatternsCondition,patternsCondition,customConditionHolder去匹配请求。当请求路径存在模式时由patternsCondition(PatternsRequestCondition)匹配请求路径。
PatternsRequestCondition.getMatchingCondition(HttpServletRequest request)
public PatternsRequestCondition getMatchingCondition(HttpServletRequest request) {
String lookupPath = UrlPathHelper.getResolvedLookupPath(request);
List<String> matches = getMatchingPatterns(lookupPath);
return !matches.isEmpty() ? new PatternsRequestCondition(new LinkedHashSet<>(matches), this) : null;
}
1、获取request中的请求路径
2、将request中的请求路径与@RequestMapping标注的URL进行模式匹配。若匹配返回PatternsRequestCondition否则返回null。调用PathMatcher.match(String pattern, String path)判断请求是否与模式匹配,即与@RequestMapping中的URL模式是否匹配。
RequestMappingInfoHandlerMapping.handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request)
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
super.handleMatch(info, lookupPath, request);
RequestCondition<?> condition = info.getActivePatternsCondition();
if (condition instanceof PathPatternsRequestCondition) {
extractMatchDetails((PathPatternsRequestCondition) condition, lookupPath, request);
}
else {
extractMatchDetails((PatternsRequestCondition) condition, lookupPath, request);
}
if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
}
}
1、调用父类的handleMatch。request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);将请求路径设置PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE属性中。
2、获取RequestCondition,如果RequestCondition是PathPatternsRequestCondition类型进行处理。否则将RequestCondition转成PatternsRequestCondition后进行处理。
3、解析producible media types并设置到属性中
RequestMappingInfoHandlerMapping.extractMatchDetails(
PatternsRequestCondition condition, String lookupPath, HttpServletRequest request)
private void extractMatchDetails(
PatternsRequestCondition condition, String lookupPath, HttpServletRequest request) {
String bestPattern;
Map<String, String> uriVariables;
if (condition.isEmptyPathMapping()) {
bestPattern = lookupPath;
uriVariables = Collections.emptyMap();
}
else {
bestPattern = condition.getPatterns().iterator().next();
uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
if (!getUrlPathHelper().shouldRemoveSemicolonContent()) {
request.setAttribute(MATRIX_VARIABLES_ATTRIBUTE, extractMatrixVariables(request, uriVariables));
}
uriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
}
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
request.setAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
}
1、判断PatternsRequestCondition中处理请求路径是否非空,若为空uriVariables设置空集合。
2、获取pathMatcher解析UriTemplateVariables,@@PathVariable就是在这里解析值的。
3、设置最匹配路径到request的BEST_MATCHING_PATTERN_ATTRIBUTE属性中
4、设置uri模板变量值到request的URI_TEMPLATE_VARIABLES_ATTRIBUTE属性中
AntPathMatcher.extractUriTemplateVariables(String pattern, String path)
public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
Map<String, String> variables = new LinkedHashMap<>();
boolean result = doMatch(pattern, path, true, variables);
if (!result) {
throw new IllegalStateException("Pattern \"" + pattern + "\" is not a match for \"" + path + "\"");
}
return variables;
}
将pattern和请求路径匹配,同时解析uri模板变量设置到Map中。比如,模式是/hotels/{hotel},路径是/hotels/1,Map的结果是hotel->1
AbstractHandlerMapping.getHandlerExecutionChain(Object handler, HttpServletRequest request)
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(request)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
1、创建HandlerExecutionChain
2、遍历adaptedInterceptors,如果interceptor是MappedInterceptor类型且匹配request,则获取Interceptor加入到HandlerExecutionChain,如果interceptor不是MappedInterceptor类型加入HandlerExecutionChain。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!