源码解析 RequestMappingHandlerMapping

本文详细探讨了Spring MVC中的RequestMappingHandlerMapping,相较于DefaultAnnotationHandlerMapping的增强之处在于其灵活的映射策略。通过分析源码,揭示了它如何维护request到处理器方法的映射,并利用RequestMappingInfo进行多条件匹配,提供了更强大的路由处理能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RequestMappingHandlerMapping 比 DefaultAnnotationHandlerMapping(DispatcherServlet的默认策略,但Spring 3.2不再推荐使用)更强大
这里写图片描述
可以看出这是一个桥接模式,其中PathMatcher、CorsProcessor、HandlerMethodMappingNamingStrategy都是接口,它们独立于HandlerMapping,使得两者都可以自由地变化


HandlerMapping 接口的唯一一个方法是getHandler(),查看 AbstractHandlerMapping 所实现的 getHandler() 源码

    //DispatcherServlet 调用此方法来获取匹配request的Handler
    @Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //获取Handler(处理器)
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }

        //如果handler是字符串,将它视为Bean的名字,并从容器中获取对应的Bean
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }

        //将handler封装成HandlerExecutionChain(包含了处理器对象和任意的拦截器)
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        //CORS(跨域资源共享)协议
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        return executionChain;
    }

    //抽象方法,由子类实现
    protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

    //获取HandlerExecutionChain(处理器执行链)
    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

        //获取当前请求路径
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        //为HandlerExecutionChain添加拦截器
        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;
    }

查看子类 AbstractHandlerMethodMapping 重写的 getHandlerInternal() 源码

    //查找Handler
@Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //获取当前请求路径
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        //读写锁
        this.mappingRegistry.acquireReadLock();
        try {
            //查找Handler(此处特指HandlerMethod)
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            if (logger.isDebugEnabled()) {
                if (handlerMethod != null) {
                    logger.debug("Returning handler method [" + handlerMethod + "]");
                }
                else {
                    logger.debug("Did not find handler method for [" + lookupPath + "]");
                }
            }
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            //释放锁
            this.mappingRegistry.releaseReadLock();
        }
    }

    //查找最为匹配的handler method
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<Match>();
        //查找匹配URL path的所有结果(非线程安全,这就是为什么前面需要加"读锁")
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
        if (directPathMatches != null) {
            //对匹配结果进行筛选(筛选因素有url、http方法、http头部、http参数等)
            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()) {
            //Match比较器,可分析匹配程度,从而得到最为匹配的结果
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            //对匹配结果进行排序,匹配程度最高的放首位
            Collections.sort(matches, comparator);
            if (logger.isTraceEnabled()) {
                logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
                        lookupPath + "] : " + matches);
            }
            Match bestMatch = matches.get(0);
            if (matches.size() > 1) {
                //判断是否为 CORS 协议的“预检请求”
                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();
                    throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
                            request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
                }
            }
            //对最优匹配的结果进行处理,可由子类重写(例如计算URI模板变量、模型变量等)
            handleMatch(bestMatch.mapping, lookupPath, request);
            //返回最优匹配的Handler(处理器),至此,整个HandlerMapping流程结束
            return bestMatch.handlerMethod;
        }
        else {
            //当匹配失败时调用(返回null),可由子类重写(尝试分析不匹配原因)
            return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
        }
    }

    //对结果进行筛选(筛选因素有url、http方法、http头部、http参数等)
    private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
        for (T mapping : mappings) {
            //从各方面检查此mapping是否匹配当前request
            T match = getMatchingMapping(mapping, request);
            if (match != null) {
                matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
            }
        }
    }

    //抽象方法,可由子类重写
    protected abstract T getMatchingMapping(T mapping, HttpServletRequest request);

this.mappingRegistry 维护着request到handler methods(处理器)的映射关系,可能有人好奇,这些数据是从哪收集而来的,这一切都归功于 AbstractHandlerMethodMapping 实现的 InitializingBean 的接口方法 afterPropertiesSet(当Bean工厂设置完所有bean的属性之后,将会调用此方法),其实现代码的作用是收集所有的 handler methods 信息,即扫描容器内所有的Bean并探测其可能包含的handler methods


查看子类 RequestMappingInfoHandlerMapping 重写的 getMatchingMapping() 源码

@Override
    protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
        return info.getMatchingCondition(request);
    }

继续查看 RequestMappingInfo 的 getMatchingCondition() 源码


@Override
    public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
        //@RequestMapping(method=...)
        RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
        //@RequestMapping(params=...)
        ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
        //@RequestMapping(headers=...)
        HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
        //@RequestMapping(consumes=...)
        ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
        //@RequestMapping(produces=...)
        ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);

        if (methods == null || params == null || headers == null || consumes == null || produces == null) {
            return null;
        }

        //URL path patterns
        PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
        if (patterns == null) {
            return null;
        }

        //自定义筛选条件
        RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
        if (custom == null) {
            return null;
        }

        //到达此处表示所有条件都符合
        return new RequestMappingInfo(this.name, patterns,
                methods, params, headers, consumes, produces, custom.getCondition());
    }

可以看到,RequestMappingHandlerMapping 比 DefaultAnnotationHandlerMapping 更强大的地方在于对RequestMappingInfo的维护,即对多方面筛选条件的支持,而后者只能通过其内部自定义拦截器的方式来补足这方面的功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值