zoukankan      html  css  js  c++  java
  • springMVC(五): 通过 HandlerMapping 获取 HandlerExecutionChain

     请求具体过程

     

    一、HandlerMapping 

     Interface to be implemented by objects that define a mapping between requests and handler objects.

        HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

    HandlerExecutionChain(包含一个处理器 handler 如HandlerMethod 对象、多个 HandlerInterceptor 拦截器对象)

    • RequestMappingHandlerMapping 的映射关系由 MappingRegistry 维护,通过多个map联结,即可找到请求对应的处理器
    • RequestMappingHandlerMapping 的映射关系初始化入口是 afterProperties 方法,因为其实现了接口 InitializingBean

    SpringMVC的请求处理过程中的路径匹配过程(AbstractHandlerMethodMapping#lookupHandlerMethod)

        protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
            List<Match> matches = new ArrayList<Match>();
            List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
            if (directPathMatches != null) {
                addMatchingMappings(directPathMatches, matches, request);
            }
            if (matches.isEmpty()) {
                // 如正则匹配、RESTFUL路径/list/{cityId}等,这里可以改进,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));
                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) {
                    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 + "}");
                    }
                }
                handleMatch(bestMatch.mapping, lookupPath, request);
                return bestMatch.handlerMethod;
            }
            else {
                return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
            }
        }

    RequestMappingHandlerMapping根据,细化匹配条件,整体的查找过程如下:

    1.1 从urlMap中直接等值匹配查找匹配条件RequestMappingInfo

    1.2 如果等值查找到匹配条件,将其添加到match条件中

    1.3 如果没有找到匹配条件,使用所有的handlerMethod的RequestMappingInfo进行匹配

    1.4 对匹配到的Match进行排序,取出最高优先级的Match,并核对是否是唯一的最高优先级

    二、获取HandlerExecutionChain(AbstractHandlerMapping#getHandler)

        @Override
        public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
         //模板方法 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 = getApplicationContext().getBean(handlerName); }      //把Handler和HandlerInterceptor包裹成HandlerExecutionChain HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }

    3.getHandlerExecutionChain调用

        protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
         //为啥这里要做判断,因为DispatchServlet里面的doDispatch调用getHandler返回的是HandlerExecutionChain HandlerExecutionChain chain
    = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); 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; }

    三、选择使用HandlerMapping

    如何选择合适的HandlerMapping

        protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            for (HandlerMapping hm : this.handlerMappings) {
                if (logger.isTraceEnabled()) {
                    logger.trace(
                            "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
                }
           //如何选择不同的HandlerMapping HandlerExecutionChain handler
    = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
  • 相关阅读:
    分享15个专业且免费的HTML5模板
    项目环境的搭建
    DNS预解析 dns-prefetch
    页面布局
    计划与准备
    Hogan的安装和使用
    代理工具--fiddle
    vue.js加入购物车小球动画
    vue.js笔记1.0
    url,href,src区别
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/8630559.html
Copyright © 2011-2022 走看看