RequestMappingHandlerMapping的运行原理

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;
                }
            }
        }
   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值