org.springframework.web.servlet.DispatcherServlet.doDispatch{
// 根据请求对象获取能处理这个请求的Handler,可能是一个HandlerMethod对象,也可能是一个Handler类,它实现了Controller接口等等
HandlerExecutionChain mappedHandler = getHandler(processedRequest);{
if (this.handlerMappings != null) {
// 遍历我们初始化的HandlerMapping,如果不自定义,默认就是提供了三个
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);{
// 返回Object是因为getHandlerInternal是一个抽象方法
// 处理请求的Handler可能是一个beanName->Bean,也可能是一个实现了Controller接口的对象,等等
Object handler = getHandlerInternal(request);{
// 根据请求找到url路径,例如:"/"
String lookupPath = initLookupPath(request);
// 根据请求对象,和请求路径,找到对应处理的HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);{
// 封装可以处理请求的Match对象,例如:@RequestMapping("/req") @GetMapping("/req");都满足get /req的请求
// 所以可以处理请求的情况有多个,所以是一个List
List<Match> matches = new ArrayList<>();
// 在mappingRegistry之前存入了pathLookup,就是每个url->requestMappingInfo的映射
// 根据路径找到可以处理的RequestMappingInfo,返回的实list,因为url可能会出现 get/post...多种 RequestMappingInfo
// 类似于快捷方式,因为如果是静态的url,那么可以直接找到,如果是@PathVariable动态的就找不到了
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);{
return this.pathLookup.get(urlPath);
}
// 如果找到了匹配的RequestMappingInfo
if (directPathMatches != null) {
// 将匹配的对象封装成Match对象,用来匹配请求
addMatchingMappings(directPathMatches, matches, request);{
// 遍历RequestMappingInfo,因为存储的时候使用的集合存的,所以需要遍历下
for (T mapping : mappings) {
// 检查此请求映射信息中的所有条件是否与所提供的请求匹配
// 并返回一个新请求映射信息,其中包含针对当前请求量身定制的条件。
// 说白了就是检验这个请求是不是满足RequestMapping设置的所有条件,例如header,consumers等等
// 如果不满足就返回空,否则返回一个新的对象,其实match.equals(mapping)==true
T match = getMatchingMapping(mapping, request);
// 如果不为空,表示可以处理这个请求,满足所有条件
if (match != null) {
// 保存起来,并且将封装HandlerMethod等信息的MappingRegistration对象封装进去
matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
}
}
}
}
// 当上面的请求url没有满足RequestMappingInfo的条件的时候matches是为空的
// 获取pathLookup没有存储这个url的映射信息,也就是没有url->requestMappingInfo的映射信息
// 当路径上添加了@PathVariables的情况下,url就匹配不到了,所以要一一遍历去找
if (matches.isEmpty()) {
// 尝试用mappingRegistry中所有的RequestMappingInfo去匹配
// 上面directPathMatches的只是类似于一个快捷方式,已经初始化过的url保存到了pathLookup
// 如果存在可以直接get出RequestMappingInfo,如果没有,只能一个一个遍历去找
// 上面有这一行的代码解释
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
// 如果找到了匹配的处理对象
// 因为matches可能有多个,例如:@RequestMapping("/req") @GetMapping("/req");都满足get /req的请求
// 那具体选择那个来处理呢
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
// 创建比较器,根据请求头,请求参数...来比较多个Matches,看哪个最合适
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
// 找到最合适的
bestMatch = matches.get(0);
// 将HandlerMethod放入请求中
// String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
// 处理匹配的信息,保存在request中
this.handleMatch(bestMatch.mapping, lookupPath, request);{
// String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);
// String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
// String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
// 获取路径上的值
// uriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
// 保存到url变量中
request.setAttribute(URI_TEMPLATE_ VARIABLES_ATTRIBUTE, uriVariables);
}
// 返回获取到的HandlerMethod
return bestMatch.getHandlerMethod();
}else{
// 根据不同条件响应异常
return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean(){
Object handler = this.bean;
// 因为handler可能存在多种情况,可能是beanName,可能实现Controller接口的类,所以要找到真正处理的那个bean对象
if (this.bean instanceof String) {
String beanName = (String) this.bean;
handler = this.beanFactory.getBean(beanName);
}
// this.getClass() == HandlerMethod.class
// 替换一些bean对象
return new HandlerMethod(this, handler);
} : null);
}
// 找了很多资料,没有找到可能成立的情况,可能是兼容老版本的配置,因为上面的Handler都会判断如果为string就从spring容器获取
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 将handler以及拦截器封装成一个HandlerExecutionChain对象
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);{
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 如果是MappedInterceptor这种蓝接触器
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// 判断这个拦截器是否可以作用当前请求
if (mappedInterceptor.matches(request)) {
// 添加进去拦截器
chain.addInterceptor(mappedInterceptor.getInterceptor());
return;
}
}
chain.addInterceptor(interceptor);
}
return chain;
}
// 是否有跨域配置
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = getCorsConfiguration(handler, request);
config.validateAllowCredentials();
// 添加一个跨域拦截器
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);{
chain.addInterceptor(0, new CorsInterceptor(config));
}
}
return executionChain;
}
// 返回handler
if (handler != null) {
return handler;
}
}
}
}
}
RequestMappingHandlerMapping的运行原理
于 2024-01-20 23:17:09 首次发布