SpringMvc源码-RequestMappingHandlerMapping

RequestMappingHandlerMapping负责将RequestMapping注解的方法与url关联起来,并且返回HandlerExecutionChain

加载过程

DispatcherServlet.initStrategies的initHandlerMappings方法中会通过读取DispatchServerlet.proeprties对HandlerMapping进行初始化,这里重点看RequestMappingHandlerMapping类

DispatcherServlet.properties的值

1
2
3
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
org.springframework.web.servlet.function.support.RouterFunctionMapping

初始化HandlerMapping

HandlerMapping,封装了是request与他的处理类HandlerMethod的映射关系,他的职责主要是通过request找到对应的handlerMapping

AbstractHandlerMethodMapping实现了InitializingBean所以在afterPropertiesSet会进行初始化工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void afterPropertiesSet() {
//调用initHandlerMethods
initHandlerMethods();
}

//从ApplicationContext扫描所有的bean, 找到并且将handler method注册到容器中【将url和handlerMethod关联】
protected void initHandlerMethods() {
//获取application中所有的bean
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
//重点方法
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}

重点方法:processCandidateBean

根据bean找到method,封装成handlerMethod注册到容器中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
} catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
//这里isHandler判断beanType是否是一个Controller【判断是否有@Controller和@RequestMapping注解】
if (beanType != null && isHandler(beanType)) {
//重点方法
detectHandlerMethods(beanName);
}
}

重点方法

detectHandlerMethods遍历bean的method方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());

if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
//遍历handler中的方法,通过getMappingForMethod返回RequestMappingInfo
// 通过方法上的RequestMapping注解,生成RequestMappingInfo,并且和Method关联
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
} catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}

//遍历method-->RequestMappingInfo 并且将method和mapping注册到 mappingRegistry中RequestMappingHandlerMapping对其进行了改写
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}

重点方法:registerHandlerMethod(handler, invocableMethod, mapping)

向容器注册HandlerMapping:registerHandlerMethod(handler, invocableMethod, mapping);
这里的mappingRegistry 是AbstractHandlerMethodMapping的内部类MappingRegistry;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}

public void register(T mapping, Object handler, Method method) {
// Assert that the handler method is not a suspending one.
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
}
this.readWriteLock.writeLock().lock();
try {
//封装成HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
//判断mapping是否已经存在,存在抛异常
validateMethodMapping(handlerMethod, mapping);
//关联 mapping-->handlerMethod
this.mappingLookup.put(mapping, handlerMethod);
//根据mapping获取url并且将Url和mapping关联起来
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}

//关联name【RequestMappingInfoHandlerMethodMappingNamingStrategy.getName】和handlerMethod
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}

//corsLookup绑定handlerMethod和corsConfig,注解或者方法上带CrossOrigin
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}

this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
} finally {
this.readWriteLock.writeLock().unlock();
}
}

至此所有的RequestMapping都注册到容器中

doDipatch时候

通过reqeust获取handler和拦截器封装成HandlerExecutionChain过程

找到在初始化时候注册的handlerMappings,调用它们的getHandler方法,具体实现在AbstraceHanlderMapping中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//根据request获取一个指定的handler,如果没找到返回null,类型是HandlerMethod,调用链路RequestMappingHandlerMapping.getHandlerInternal-->AbstractHandlerMethodMapping.getgetHandlerInternal

//重点方法1
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);
}

//重点方法2 返回HandlerExecutionChain【handler和拦截器】的封装
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
} else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}

if (hasCorsConfigurationSource(handler)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}

return executionChain;
}

重点方法1 getHandlerInternal

这里的实现见:AbstractHandlerMethodMapping.getgetHandlerInternal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取urlPath用于查找HandlerMethod
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
//查找HandlerMethod 优先通过Path找,没找到轮询mappingLookup,之后对找到的HandlerMethod排序找到最合适的HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//re-create bean 享元模式防止请求修改HandlerMethod
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
} finally {
this.mappingRegistry.releaseReadLock();
}
}

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
//
List<Match> matches = new ArrayList<>();
//通过path查找到符合要求的RequestMappingInfo
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}

//如果通过path没找到去mappingLookup轮询一遍查找
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}

//不为空
if (!matches.isEmpty()) {
//根据RequestMappingInfoHandlerMapping.getMappingComparator排序Match.mapping的Compare然后取第一个
// todo 优先级未看
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
//排序后取第一个作为返回结果
Match bestMatch = matches.get(0);
//取出来俩个然后优先级一样直接抛出异常意思是Handler重复"多个优先级"
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
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();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
//为request设置值:PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE,返回对应的handlerMethod
//这里其实就是把mapping,和handler都返回只不过mapping放在了requst里
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
} else {
//都没匹配到调用该方法见RequestMappingInfoHandlerMapping,其中不符合RequestMappingInfo的会抛异常
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}

重点方法2 getHandlerExecutionChain

返回handler和拦截器的封装,注:springboot的WebMvcConfigurer.addInterceptors方法中添加的拦截器会转成MappedInterceptor添加到RRequestMappingHandlerMapping中代码可以从WebMvcAutoConfiguration中看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//如果是一个存在的HandlerExecutionChain,直接返回,否则new一个HandlerExecutionChain
//new HandlerExecutionChain(handler)在HandlerExecutionChain的构造方法里会再判断下Handler的类型,
// 如果是HandlerExecutionChain进行merge
// 如果是HandlerMethod会进行赋值具体见HandlerExecutionChain构造方法
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
//处理拦截器,
// 如果是MappedInterceptor,判断lookupPath是否匹配如果匹配将拦截器加入到HandlerExecutionChain
// 如果是HandlerInterceptor 或者WebRequestInterceptor直接将拦截器加入到HandlerExecutionChain
// todo 注意:springboot 通过WebMvcConfigurer配置的interceptor最终都会转成MappedInterceptor,
// 见InterceptorRegistration.getInterceptor(),入口在WebMvcAutoConfiguration.requestMappingHandlerMapping()方法
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;
}

返回了包含handler和interceptor的HandlerExecutionChain为下一步handlerAdapter执行做好准备

附录:MappingRegistry几个重要的容器

上面提到的register过程中涉及到了MappingRegistry类,它包含了几个重要容器用来缓存url,RequestMappingInfo HandlerMethod的对应关系

  • urlLookup: url–>List<RequestMappingInfo>
  • mappingLookup:RequestMappingInfo–>HandlerMethod

附录:@RequestMapping注解

RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

  • value:指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
  • method:指定请求的method类型, GET、POST、PUT、DELETE等;
  • consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
  • produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
  • params:指定request中必须包含某些参数值是,才让该方法处理。
  • headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。