spring源码解析-web系列(一):启动
spring源码解析-web系列(二):处理请求的过程
spring源码解析-web系列(三):九大组件之HandlerMapping
spring源码解析-web系列(四):九大组件之HandlerAdapter
spring源码解析-web系列(五):解析请求参数
spring源码解析-web系列(六):九大组件之ViewResolver
spring源码解析-web系列(七):九大组件之HandlerExceptionResolver
转载请标明出处:
https://blog.csdn.net/bingospunky/article/details/97795113
本文出自马彬彬的博客
HandlerMapping
HandlerMapping的作用就是通过HttpServletRequest查找Handler,Handler后面可以用来处理逻辑的单元,比如我们配置的一个 @RequestMapping 注解的方法,一个***org.springframework.web.servlet.mvc.Controller***类(该接口已经被废弃了,推荐使用注解)。
HandlerMapping接口就定义了一个方法:
HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception
该方法返回HandlerExecutionChain对象,HandlerExecutionChain是对Handler的封装,它包含Handler和HandlerInterceptor,对HandlerInterceptor的调用是通过HandlerExecutionChain来调用的。
HandlerMapping的继承关系如下:
图1:
从继承关系来看,HandlerMapping分为两大类:左边是基于Method的注解来匹配;右边是url来匹配。
DispatcherServlet加载时,默认就加载两个HandlerMapping,一个是RequestMappingHandlerMapping,另一个是BeanNameUrlHandlerMapping。
AbstractHandlerMapping
HandlerMapping的整体结构在AbstractHandlerMapping中实现,根据request查找Handler和Interceptors,组合成HandlerExecutionChain返回。
查找Handler的过程通过***getHandlerInternal***让子类去实现,查找Interceptors的过程在如下代码中。
代码0 (org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandlerExecutionChain):
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
chain.addInterceptors(this.getAdaptedInterceptors());
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
Iterator var5 = this.mappedInterceptors.iterator();
while(var5.hasNext()) {
MappedInterceptor mappedInterceptor = (MappedInterceptor)var5.next();
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
AbstractUrlHandlerMapping
代码1 (org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.getHandlerInternal):
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
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.
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
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;
}
其中代码1第4行lookupHandler方法和第22行buildPathExposingHandler方法比较关键。
代码1第4行代码通过url路径和HttpServletRequest查找Handler,在AbstractUrlHandlerMapping中有一个***private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();***,url和Handler在初始化的时候存放在这个handlerMap中。
代码2 (org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.lookupHandler):
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// Direct match?
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// 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;
}
代码2第3行直接根据url获取Handler,如果获取到就直接返回。有可能获取不到,比如url带参数或者有通配符,这时通过代码2第14第24行代码进行模式匹配,可能匹配到若干个url。然后通过代码2第26第33行代码把获取到url进行排序,取出第一个url便是最合适的url。排序的过程如下:
代码3 (org.springframework.util.AntPathMatcher.AntPatternComparator.compare(String pattern1, String pattern2)):
@Override
public int compare(String pattern1, String pattern2) {
PatternInfo info1 = new PatternInfo(pattern1);
PatternInfo info2 = new PatternInfo(pattern2);
if (info1.isLeastSpecific() && info2.isLeastSpecific()) {
return 0;
}
else if (info1.isLeastSpecific()) {
return 1;
}
else if (info2.isLeastSpecific()) {
return -1;
}
boolean pattern1EqualsPath = pattern1.equals(path);
boolean pattern2EqualsPath = pattern2.equals(path);
if (pattern1EqualsPath && pattern2EqualsPath) {
return 0;
}
else if (pattern1EqualsPath) {
return -1;
}
else if (pattern2EqualsPath) {
return 1;
}
if (info1.isPrefixPattern() && info2.getDoubleWildcards() == 0) {
return 1;
}
else if (info2.isPrefixPattern() && info1.getDoubleWildcards() == 0) {
return -1;
}
if (info1.getTotalCount() != info2.getTotalCount()) {
return info1.getTotalCount() - info2.getTotalCount();
}
if (info1.getLength() != info2.getLength()) {
return info2.getLength() - info1.getLength();
}
if (info1.getSingleWildcards() < info2.getSingleWildcards()) {
return -1;
}
else if (info2.getSingleWildcards() < info1.getSingleWildcards()) {
return 1;
}
if (info1.getUriVars() < info2.getUriVars()) {
return -1;
}
else if (info2.getUriVars() < info1.getUriVars()) {
return 1;
}
return 0;
}
代码4 (org.springframework.util.AntPathMatcher.AntPatternComparator.PatternInfo相关代码):
public PatternInfo(String pattern) {
this.pattern = pattern;
if (this.pattern != null) {
initCounters();
this.catchAllPattern = this.pattern.equals("/**");
this.prefixPattern = !this.catchAllPattern && this.pattern.endsWith("/**");
}
if (this.uriVars == 0) {
this.length = (this.pattern != null ? this.pattern.length() : 0);
}
}
protected void initCounters() {
int pos = 0;
while (pos < this.pattern.length()) {
if (this.pattern.charAt(pos) == '{') {
this.uriVars++;
pos++;
}
else if (this.pattern.charAt(pos) == '*') {
if (pos + 1 < this.pattern.length() && this.pattern.charAt(pos + 1) == '*') {
this.doubleWildcards++;
pos += 2;
}
else if (pos > 0 && !this.pattern.substring(pos - 1).equals(".*")) {
this.singleWildcards++;
pos++;
}
else {
pos++;
}
}
else {
pos++;
}
}
}
通过代码3和代码4可以发现,在对url进行比较的时候,先判这个url是不是形如*** /** 的全匹配,再对url进行计算有多少个匹配参数、单星号通配符、双星号通配符。最后根据这些数据得出结论,比如形如 /** ***的全匹配优先级最低、字符串完全匹配优先级最高、不包含变量时,长度越长约优先、相同长度时变量越少越优先等。
代码2第50~57行从url里提取参数。代码2第61行buildPathExposingHandler方法把Handler构造成HandlerExecutionChain,并且添加PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor两个内部拦截器。
AbstractUrlHandlerMapping的子类
SimpleUrlHandlerMapping: 直接把url和Handler对象存放在map里,在初始化的时候调用registerHandler方法注册。
AbstractDetectingUrlHandlerMapping: 抽象类,从BeanFactory获取所有的Bean,获取该Bean对应的url,如果url存在,则注册url和Bean对象。通过Bean获取url的过程有子类具体实现。
AbstractControllerUrlHandlerMapping: 抽象类,也是AbstractDetectingUrlHandlerMapping的子类,通过一个Bean是否是***org.springframework.web.servlet.mvc.Controller***的子类或者是否被@Controller注解来判断一个Bean是否可以作为Handler。它有两个子类,区别是构造url的方式不同,一个使用beanName构造,一个使用ClassName构造。
AbstractHandlerMethodMapping
AbstractHandlerMethodMapping类中有三个Map:
代码5 (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping):
private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap();
private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap();
private final MultiValueMap<String, HandlerMethod> nameMap = new LinkedMultiValueMap();
handlerMethods: 存放匹配条件(RequestCondition,也就是@RequestMapping注解对应的信息)和HandlerMethod的匹配关系。
urlMap: 存放url和RequestCondition的匹配关系,这里Map的类型为MultiValueMap,一个url可能会对应多个@RequestMapping。
nameMap: 暂不考虑。
AbstractHandlerMethodMapping初始化过程
AbstractHandlerMethodMapping的初始化是在initHandlerMethods方法进行的。
代码6 (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods):
protected void initHandlerMethods() {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Looking for request mappings in application context: " + this.getApplicationContext());
}
String[] beanNames = this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.getApplicationContext(), Object.class) : this.getApplicationContext().getBeanNamesForType(Object.class);
String[] var2 = beanNames;
int var3 = beanNames.length;
for(int var4 = 0; var4 < var3; ++var4) {
String beanName = var2[var4];
if (!beanName.startsWith("scopedTarget.") && this.isHandler(this.getApplicationContext().getType(beanName))) {
this.detectHandlerMethods(beanName);
}
}
this.handlerMethodsInitialized(this.getHandlerMethods());
}
代码6第6行获取到BeanFactory里的所有对象,如果该对象包含@Controller注解或@RequestMapping注解,那么调用代码6第16行代码探测该对象里的方法。
代码7 (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods):
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = handler instanceof String ? this.getApplicationContext().getType((String)handler) : handler.getClass();
final Map<Method, T> mappings = new IdentityHashMap();
final Class<?> userType = ClassUtils.getUserClass(handlerType);
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
public boolean matches(Method method) {
T mapping = AbstractHandlerMethodMapping.this.getMappingForMethod(method, userType);
if (mapping != null) {
mappings.put(method, mapping);
return true;
} else {
return false;
}
}
});
Iterator var6 = methods.iterator();
while(var6.hasNext()) {
Method method = (Method)var6.next();
this.registerHandlerMethod(handler, method, mappings.get(method));
}
}
代码7传地进来的参数是对象或者对象的beanName,这里把该对象叫做Handler,同时也把它里面的方法叫做Handler,为了区分他们,分别叫他们为对象Handler和Handler。
代码7第3行创建的mappings存放Method和RequestCondition的对应关系。遍历该对象Handler里的所有方法,通过代码7第7行的getMappingForMethod方法获取RequestCondition,获取的逻辑就是判断该方法是否被@RequestMapping注解,如果被注解,通过该注解和类上的注解一起构造RequestCondition对象。对于获取到RequestCondition的方法,把该方法和RequestCondition放进mappings里。
代码7第20行代码,遍历mappings进行注册。
代码8 (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod):
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
HandlerMethod newHandlerMethod = this.createHandlerMethod(handler, method);
HandlerMethod oldHandlerMethod = (HandlerMethod)this.handlerMethods.get(mapping);
if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() + "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" + oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
} else {
this.handlerMethods.put(mapping, newHandlerMethod);
if (this.logger.isInfoEnabled()) {
this.logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
}
Set<String> patterns = this.getMappingPathPatterns(mapping);
Iterator var7 = patterns.iterator();
while(var7.hasNext()) {
String pattern = (String)var7.next();
if (!this.getPathMatcher().isPattern(pattern)) {
this.urlMap.add(pattern, mapping);
}
}
if (this.namingStrategy != null) {
String name = this.namingStrategy.getName(newHandlerMethod, mapping);
this.updateNameMap(name, newHandlerMethod);
}
}
}
代码8主要的内容就是把找到的Handler注册到HandlerMapping里。
代码8第2行通过对象(或beanName)和Method构造HandlerMethod,代码8第7行把RequestCondition(mapping对象)和Handler(newHandlerMethod对象)存放在handlerMethods里。代码8第12~20行代码通过RequestCondition(mapping对象)获取url,然后把url和RequestCondition(mapping对象)的关系存放在urlMap里。
至此,AbstractHandlerMethodMapping初始化过程就结束了。
AbstractHandlerMethodMapping执行过程
AbstractHandlerMethodMapping作为AbstractHandlerMapping的子类,在执行过程中,最重要的方法就是getHandlerInternal。
代码9 (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal):
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Looking up handler method for path " + lookupPath);
}
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
if (this.logger.isDebugEnabled()) {
if (handlerMethod != null) {
this.logger.debug("Returning handler method [" + handlerMethod + "]");
} else {
this.logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
}
代码9第7行代码,通过url和HttpServletRequest获取HandlerMethod。
代码10 (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod):
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
List<T> directPathMatches = (List)this.urlMap.get(lookupPath);
if (directPathMatches != null) {
this.addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
this.addMatchingMappings(this.handlerMethods.keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
Collections.sort(matches, comparator);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
}
AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)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 + "}");
}
}
this.handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
} else {
return this.handleNoMatch(this.handlerMethods.keySet(), lookupPath, request);
}
}
代码10第三行通过url获取RequestCondition,代码10第5行使用这些RequestCondition对HttpServletRequest进行匹配,如果匹配成功,把他们添加到matches中。代码10第13行~27行在匹配的matches中选择一个最合适的HandlerMethod。