前言:
上篇我们分析了 Spring MVC 的工作流程源码,其核心是 DispatcherServlet#doDispatch 方法,这个方法中有获取映射器处理器操作,也就是调用 DispatcherServlet#getHandler 方法,本篇我们重点分析一下 DispatcherServlet#getHandler 的实现原理。
Spring MVC 知识传送门:
DispatcherServlet#getHandler 方法源码分析
DispatcherServlet#getHandler 方法就是从 HandlerMapping 中查询匹配当前 request 的 Handler,只要找到了就不在循环直接返回,我们我们重点关注 mapping.getHandler(request) 这行代码,这里实际调用的是接口的抽象类 AbstractHandlerMapping 中的 getHandler 方法,下面接着分析。
java
//org.springframework.web.servlet.DispatcherServlet#getHandler
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//this.handlerMappings 为空判断 DispatcherServlet 初始化时注册的 handlerMapping
if (this.handlerMappings != null) {
//不为空 迭代遍历
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
//获取具体的 HandlerExecutionChain 重点关注
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
//不为空 返回
return handler;
}
}
}
return null;
}
AbstractHandlerMapping#getHandler 方法源码分析
AbstractHandlerMapping#getHandler 方法主要作用是获取当前请求的 HandlerExecutionChain,HandlerExecutionChain 包含了 HandlerMapping 和 拦截器,同时也对跨域请求做了一些处理,我们重点关注获取 Handler 和返回拦截器链的部分。
java
//org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取调用方法的 handler 重点关注
Object handler = this.getHandlerInternal(request);
//handler 为空判断
if (handler == null) {
//为空 获取默认的handler
handler = this.getDefaultHandler();
}
//再次为空判断
if (handler == null) {
//还为空 直接返回
return null;
} else {
//handler 是否是 String 类型
if (handler instanceof String) {
//获取 hanlerName
String handlerName = (String)handler;
//从容器中获取具体的 handler
handler = this.obtainApplicationContext().getBean(handlerName);
}
//获取当前请求的拦截器执行链 重点关注
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
//跨域相关处理
if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
config = config != null ? config.combine(handlerConfig) : handlerConfig;
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
//返回拦截器链
return executionChain;
}
}
AbstractHandlerMethodMapping#getHandlerInternal 方法源码分析
getHandlerInternal 方法是由 AbstractHandlerMapping 子类实现的,比如 AbstracUrlHandlerMapping、AbstractHandlerMethodMapping, 这里我们分析 AbstractHandlerMethodMapping#getHandlerInternal 方法,当前方法为了线程安全加了读锁,方法本身没有太多的逻辑,从 Request 中获取到 urlPaht 之后,就继续调用本类的 lookupHandlerMethod 方法,返回 HandlerMethod。
java
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//从request 中解析出 urlpath
String lookupPath = this.initLookupPath(request);
//加读锁
this.mappingRegistry.acquireReadLock();
HandlerMethod var4;
try {
//根据 urlpath 和 request 寻找具体的 HandlerMethod 重点关注
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
} finally {
//释放读锁
this.mappingRegistry.releaseReadLock();
}
return var4;
}
AbstractHandlerMethodMapping#lookupHandlerMethod 方法源码分析
AbstractHandlerMethodMapping#lookupHandlerMethod 方法就是根据 Request 的请求路径找到 HandlerMethaod,吐如果根据一一系列的匹配规则还是匹配不到,就给出匹配不到的提示,这里我们重点关注 this.handleMatch(bestMatch.mapping, lookupPath, request) 这行代码,这里面有对请求路径后拼接参数的处理。
java
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod
//根据 urlpath 和 request 寻找具体的 HandlerMethod
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
//根据 url 从 mappingRegistry 中获取 RequestMappingInfo
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
//不为空 添加到 matches 中
this.addMatchingMappings(directPathMatches, matches, request);
}
//matches 为空判断
if (matches.isEmpty()) {
//根据 urlpath 匹配到的结果为空 就将所有的映射关系加入 matches
this.addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
//再次为空判断
if (matches.isEmpty()) {
//为空 处理
return this.handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
} else {
//获取第一个
AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
//排序
Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
matches.sort(comparator);
//获取排序后的第一个
bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace(matches.size() + " matching mappings: " + matches);
}
//是否是跨域请求
if (CorsUtils.isPreFlightRequest(request)) {
Iterator var7 = matches.iterator();
while(var7.hasNext()) {
AbstractHandlerMethodMapping<T>.Match match = (AbstractHandlerMethodMapping.Match)var7.next();
//有跨域配置
if (match.hasCorsConfig()) {
//返回跨域配置的 handlermethod
return PREFLIGHT_AMBIGUOUS_MATCH;
}
}
} else {
//普通请求 获取匹配到的第一个
AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)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 + "}");
}
}
}
//将匹配到的HandlerMethod 设置到 request 中
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
//获取到的请求 mapping 进行处理 主要是针对pattern类型进行 请求路径 url 和请求参数的解析 存放到request
this.handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
}
RequestMappingInfoHandlerMapping#handleMatch方法源码分析
RequestMappingInfoHandlerMapping#handleMatch 方法主要是对获取到的 RequestMappingInfo 对象中的方法的请求路径和参数进行处理,并设置到 Request 属性值中,这里主要区分了请求路径后面拼接参数和不拼接参数两种情况的处理,重点关注this.extractMatchDetails 方法。
java
//org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleMatch
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
//调用父类的方法存储 urlpath
super.handleMatch(info, lookupPath, request);
//获取活跃的 Pattern 条件
RequestCondition<?> condition = info.getActivePatternsCondition();
//是否是 PathPatternsRequestCondition 类型
if (condition instanceof PathPatternsRequestCondition) {
//是 /order/queryorder
this.extractMatchDetails((PathPatternsRequestCondition)condition, lookupPath, request);
} else {
//否 例如 /order/queryorder/{id}
this.extractMatchDetails((PatternsRequestCondition)condition, lookupPath, request);
}
//方法的 @RequestMapping 修饰的方法是否包含 produces 属性
if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
//context-type 中的 mediaTypes 存储到request
request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
}
}
RequestMappingInfoHandlerMapping#extractMatchDetails 方法源码分析
RequestMappingInfoHandlerMapping#extractMatchDetails 方法主要是针对 url 上是否拼接变量值进行了处理,并把解析出来的属性设置给 Request。
java
//org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#extractMatchDetails
private void extractMatchDetails(PathPatternsRequestCondition condition, String lookupPath, HttpServletRequest request) {
PathPattern bestPattern;
Map uriVariables;
//路径模式请求条件 是否为空
if (condition.isEmptyPathMapping()) {
//为空 获取第一个 pattern
bestPattern = condition.getFirstPattern();
//url 变量赋值为空
uriVariables = Collections.emptyMap();
} else {
//获取解析后的 PathContainer
PathContainer path = ServletRequestPathUtils.getParsedRequestPath(request).pathWithinApplication();
//获取第一个
bestPattern = condition.getFirstPattern();
//根据 PathContainer 进行匹配
PathMatchInfo result = bestPattern.matchAndExtract(path);
Assert.notNull(result, () -> {
return "Expected bestPattern: " + bestPattern + " to match lookupPath " + path;
});
//获取 url 上的变量
uriVariables = result.getUriVariables();
//作为属性设置给 Request
request.setAttribute(MATRIX_VARIABLES_ATTRIBUTE, result.getMatrixVariables());
}
//设置到 request
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern.getPatternString());
request.setAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
}
//org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#extractMatchDetails
private void extractMatchDetails(PatternsRequestCondition condition, String lookupPath, HttpServletRequest request) {
String bestPattern;
Map uriVariables;
if (condition.isEmptyPathMapping()) {
//为空直接赋值为 urlpath
bestPattern = lookupPath;
//变量赋值为空
uriVariables = Collections.emptyMap();
} else {
//不为空
bestPattern = (String)condition.getPatterns().iterator().next();
//获取变量值 {id} 对应的值
uriVariables = this.getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
if (!this.getUrlPathHelper().shouldRemoveSemicolonContent()) {
//作为属性设置给 Request
request.setAttribute(MATRIX_VARIABLES_ATTRIBUTE, this.extractMatrixVariables(request, uriVariables));
}
//对路径进行编码
uriVariables = this.getUrlPathHelper().decodePathVariables(request, uriVariables);
}
//设置到 request
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
request.setAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
}
AbstractHandlerMapping#getHandlerExecutionChain 方法源码分析
AbstractHandlerMapping#getHandlerExecutionChain 方法的主要作用就是构造一个 HandlerExecutionChain,会把传入的 handler 和所有拦截器通过责任链模式构造成一个 HandlerExecutionChain,当调用这个 handler 时就会通过这个责任链执行拦截器内的处理方法。
java
//org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//handler 是否是 HandlerExecutionChain 类型 是 强转 不是 就用 handler 创建一个 HandlerExecutionChain
HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
//获取适配器拦截器 循环遍历
Iterator var4 = this.adaptedInterceptors.iterator();
while(var4.hasNext()) {
HandlerInterceptor interceptor = (HandlerInterceptor)var4.next();
//interceptor 是否是映射器拦截器 MappedInterceptor
if (interceptor instanceof MappedInterceptor) {
//是 强转
MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
//是否能匹配到当前 Request
if (mappedInterceptor.matches(request)) {
//是 添加到 chain中
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
//不是 可能是普通拦截器 加入到 chain 中
chain.addInterceptor(interceptor);
}
}
//返回 chain
return chain;
}
本文简单分析了 Spring MVC 工作流程中获取 Handler 的实现,整个过程先通过 Request 请求的一些属性,从整个 HandlerMapping 中获取到具体的 Handler,然后和当前请求应该使用的拦截器一起,通过责任链模式构造出一个拦截器链,看似是从 HandlerMapping 中获取处理当前请求的 Handler,实则最后返回的是一个拦截器链,希望本篇的细节剖析可以帮助大家建立更深的映像。
欢迎提出建议及对错误的地方指出纠正。