RequestMappingHandlerMapping 比 DefaultAnnotationHandlerMapping(DispatcherServlet的默认策略,但Spring 3.2不再推荐使用)更强大
可以看出这是一个桥接模式,其中PathMatcher、CorsProcessor、HandlerMethodMappingNamingStrategy都是接口,它们独立于HandlerMapping,使得两者都可以自由地变化
HandlerMapping 接口的唯一一个方法是getHandler(),查看 AbstractHandlerMapping 所实现的 getHandler() 源码
//DispatcherServlet 调用此方法来获取匹配request的Handler
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取Handler(处理器)
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
//如果handler是字符串,将它视为Bean的名字,并从容器中获取对应的Bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//将handler封装成HandlerExecutionChain(包含了处理器对象和任意的拦截器)
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
//CORS(跨域资源共享)协议
if (CorsUtils.isCorsRequest(request)) {
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;
}
//抽象方法,由子类实现
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
//获取HandlerExecutionChain(处理器执行链)
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
//获取当前请求路径
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
//为HandlerExecutionChain添加拦截器
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;
}
查看子类 AbstractHandlerMethodMapping 重写的 getHandlerInternal() 源码
//查找Handler
@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 {
//查找Handler(此处特指HandlerMethod)
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();
}
}
//查找最为匹配的handler method
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
//查找匹配URL path的所有结果(非线程安全,这就是为什么前面需要加"读锁")
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//对匹配结果进行筛选(筛选因素有url、http方法、http头部、http参数等)
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()) {
//Match比较器,可分析匹配程度,从而得到最为匹配的结果
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) {
//判断是否为 CORS 协议的“预检请求”
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 + "}");
}
}
//对最优匹配的结果进行处理,可由子类重写(例如计算URI模板变量、模型变量等)
handleMatch(bestMatch.mapping, lookupPath, request);
//返回最优匹配的Handler(处理器),至此,整个HandlerMapping流程结束
return bestMatch.handlerMethod;
}
else {
//当匹配失败时调用(返回null),可由子类重写(尝试分析不匹配原因)
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
//对结果进行筛选(筛选因素有url、http方法、http头部、http参数等)
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
//从各方面检查此mapping是否匹配当前request
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
//抽象方法,可由子类重写
protected abstract T getMatchingMapping(T mapping, HttpServletRequest request);
this.mappingRegistry 维护着request到handler methods(处理器)的映射关系,可能有人好奇,这些数据是从哪收集而来的,这一切都归功于 AbstractHandlerMethodMapping 实现的 InitializingBean 的接口方法 afterPropertiesSet(当Bean工厂设置完所有bean的属性之后,将会调用此方法),其实现代码的作用是收集所有的 handler methods 信息,即扫描容器内所有的Bean并探测其可能包含的handler methods
查看子类 RequestMappingInfoHandlerMapping 重写的 getMatchingMapping() 源码
@Override
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
return info.getMatchingCondition(request);
}
继续查看 RequestMappingInfo 的 getMatchingCondition() 源码
@Override
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
//@RequestMapping(method=...)
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
//@RequestMapping(params=...)
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
//@RequestMapping(headers=...)
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
//@RequestMapping(consumes=...)
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
//@RequestMapping(produces=...)
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
if (methods == null || params == null || headers == null || consumes == null || produces == null) {
return null;
}
//URL path patterns
PatternsRequestCondition 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, patterns,
methods, params, headers, consumes, produces, custom.getCondition());
}
可以看到,RequestMappingHandlerMapping 比 DefaultAnnotationHandlerMapping 更强大的地方在于对RequestMappingInfo的维护,即对多方面筛选条件的支持,而后者只能通过其内部自定义拦截器的方式来补足这方面的功能