分析第二个体系
AbstractUrlHandlerMapping系列
通过url来进行匹配。
此系列的大致原理是
将url和对应的Handler保存在一个Map中,
在getHandlerInternal方法使用url从map中获取Handler。
映射过程自己实现,
而map的初始化交给具体的子类去完成
handlerMap 还有一个处理’/’的rootHandler.
第一步,首先看父类中没有实现的一个方法
getHandlerInternal
//获取Handler,主要是通过url和method的对应关系来查找
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
//获取request中的请求链接
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
//根据链接查找handler
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
//定义一个变量,保存找到的原始Handler
Object rawHandler = null;
//如果lookupPath为"/",使用rootHandler
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
//如果没有使用一个默认的
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
//如果是String类型则到容器中查找具体的Bean
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Mapping [" + lookupPath + "] to " + handler);
}
//没有映射路径
else if (handler == null && logger.isTraceEnabled()) {
logger.trace("No handler mapping found for [" + lookupPath + "]");
}
return handler;
}
看来从map中获取handler分为两步
1.获取request中的请求链接
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
2.根据请求链接查找handler
Object handler = lookupHandler(lookupPath, request);
首先是通过lookupHandler方法来查找Handler,这里我们看到了之前说的Map对象,用来存储url和Handler之间的关系,当Handler获取为String时需要从Bean容器中获取注入的实现类,当然在查找过程中也会有模糊匹配等查找过程。
来分析一下lookupHandler
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// Direct match?
//直接从map中获取 根据key获取value
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
//如果是String类型则从容器中获取
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//验证是否合是正确格式
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
//在map中没有获取到
// Pattern match?
//通过模糊匹配来查找
List<String> matchingPatterns = new ArrayList<String>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern +"/");
}
}
}
String bestPatternMatch = null;
//匹配规则
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
if (logger.isDebugEnabled()) {
logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
}
bestPatternMatch = matchingPatterns.get(0);
}
if (bestPatternMatch != null) {
handler = this.handlerMap.get(bestPatternMatch);
if (handler == null) {
Assert.isTrue(bestPatternMatch.endsWith("/"));
handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
// for all of them
Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isDebugEnabled()) {
logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
}
return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
}
// No handler found...
return null;
}
感觉主要是匹配规则复杂 多看看就明白了
上面两个方法介绍了通过url来查找handlerMap获取handler的操作,AbstractUrlHandlerMapping中也提供了注册url和handler到handlerMap中的操作,具体的调用则要到AbstractUrlHandlerMapping的子类中实现。
通过上面介绍我们知道AbstractUrlHandlerMapping提供的功能就是根据url从handlerMap中获取handler和注册url和handler的对应关系到handlerMap中,当然这个过程中还包含很多其他的操作。
另一个重要方法 bindPathExposingHandler。
第二步 然后是map的初始化
初始化map有两种方式
1. 手工在配置文件中注册
2. 另一种在spring容器里寻找 需要赛选
在registerHandler方法进行,有两个方法
具体子类的实现SimpleUrlHandlerMapping
AbstractDetectingUrlHandlerMapping有3个子类
BeanName AbstractController
AbstractHandlerMethodMapping
只有3个类
RequestMappingInfoHandlerMapping
RequestMappingHandlerMapping
该系列是将Method作为Handler来使用 比如@RequestMapping 所注释的方法就是这种Handler 该系列匹配内容比较多,直接匹配到Method。
器用分析法
内部3个map
handlerMethods
urlMap
nameMap
整个过程使用Match作为载体,内部类封装了匹配条件和HandlerMethod
查找interceptors是通过几个相关map完成
完整代码点这里–》
//******************************************************