1.确定由哪个controller处理这次请求
HandlerMapping(处理器映射器)可以将请求映射到对应的Handler(controller)上
一个请求进来,想要处理这个请求,首先得确定由哪个方法处理,这个功能由requestMappingHandlerMapping以及他的父类们共同完成,调用这些类的成员方法完成。
请求进来会到DispatcherServlet类的doDispatch方法
通过 getHandler方法 就获得了当前请求的处理对象,也就是controller。
1.getHandler方法
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//遍历handlerMappings 一共有5个 这里用到requestMappingHandlerMapping 在mvcAutoConfigue会自动导入 handlerMappings会在第一次请求时调用initHandlerMappings完成导入
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
//找到实际的处理方法 也就是controller 这里注意类型是HandlerExecutionChain
//这里边有handler和 HandlerInterceptor
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
WebMvcAutoConfiguration.java中自动导入requestMappingHandlerMapping
第一次访问时,初始化handlerMappings ,一共5个
2.继续调用requestMappingHandlerMapping的getHandler方法
这个是在AbstractHandlerMapping类中
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取handler 也就是controller
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);
}
//封装成HandlerExecutionChain 类型
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;
}
3.getHandlerInternal方法
RequestMappingHandlerMapping类中
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
try {
//调用父类的getHandlerInternal方法
return super.getHandlerInternal(request);
}
finally {
ProducesRequestCondition.clearMediaTypesAttribute(request);
}
}
4.继续getHandlerInternal方法
1.从request中获取到对应的请求路径 UrlPathHelper是一个工具类获取请求路径
2.根据请求路径获取到合适的HandlerMethod对象并返回
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取到请求的路径 (找到controller就通过这个路径)
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
//将解析出来的请求路径放入request 方便后续直接从request中获取使用
request.setAttribute(LOOKUP_PATH, lookupPath);
//加锁
this.mappingRegistry.acquireReadLock();
try {
//主要方法 找到controller
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//对HandlerMethod进行实例赋值(因为HanlerMethod中的bean属性是该方法对应对应的类对象
//这里通过createWithResolvedBean会将spring容器中的HandlerMethod所属的bean实例赋值)
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
//释放锁
this.mappingRegistry.releaseReadLock();
}
}
5.lookupHandlerMethod方法
根据请求request和对应的请求路径lookupPath获取对应的HandlerMethod
在AbstractHandlerMethodMapping类中
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
//创建集合 用来存储请求路径和处理方法(controller)
List<Match> matches = new ArrayList<>();
//获取到直接路径 也就是controller上配置的路径
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//找到完全匹配的则将mappings、handlerMethod 添加到matches中
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()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
//获取到最佳的Match 也就是最佳的controller
Match bestMatch = matches.get(0);
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 + "}");
}
}
//将匹配的HandlerMethod 存放到request中 方便后期使用
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
//获取的请求mapping进行处理(主要是针对pattern类型进行 请求路径url和请求参数的解析存放request)Pattern模式:localhost:port/context/book/book/{id}有不确定的参数
handleMatch(bestMatch.mapping, lookupPath, request);
//返回这个最佳controller
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
至此就把这个congtroller选出来了。
总结:
1.请求进来先调用doDispatch方法。
2.调用DispatcherServlet类的getHandler方法。遍历handlerMappings ,调用getHandler方法,如果可以获取到handler,就返回,跳出遍历。这里在第一个循环就会找到handler(controller),标注了@xxxMapping注解的controler都会通过requestMappingHandlerMapping实现。
3.继续调用requestMappingHandlerMapping的getHandler方法,执行getHandlerInternal方法(最终会调用AbstractHandlerMethodMapping类的getHandlerInternal方法),然后将获取到的handler封装成HandlerExecutionChain类型返回,这个类中有handler和 HandlerInterceptor。
4.AbstractHandlerMethodMapping类的getHandlerInternal方法会调用lookupHandlerMethod方法,然后将获取到的handler也就是controller返回。
5.lookupHandlerMethod会根据请求路径,找到最佳的handler(controller)返回。
6.最终返回到doDispatch类中,DispatcherServlet类的getHandler方法完成。获取到HandlerExecutionChain类型的mappedHandler。
大致流程是这样,其中有太多细节,具体是怎么通过路径获取到的controller的呢,肯定是在最后的lookupHandlerMethod方法中实现,还需要细细研究啊~~~