美文网首页消息队列
springmvc源码分析-HandlerMapping工作流程

springmvc源码分析-HandlerMapping工作流程

作者: hello_kd | 来源:发表于2020-11-07 16:26 被阅读0次

之前的一篇HandlerMapping初始化流程,讲述了HandlerMapping的初始化流程,本文就来看下HandlerMapping的工作流程,主要就是根据http请求查找到对应的controller,还会加上一些拦截器,然后执行拦截器与controller的方法。

springmvc的请求入口都是DispatcherServlet的doDispatch方法,方法内部的这行代码就是请求映射到handler处理逻辑

mappedHandler = getHandler(processedRequest);

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

getHandler中,循环容器的所有HandlerMapping,执行mapping的getHandler,若不为null,说明匹配了。这里HandlerMapping的执行顺序就是通过mapping的order属性指定的,这里返回的是HandlerExecutionChain 对象,因为会存在一些拦截器,在请求处理方法的前后加一些逻辑。

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 = obtainApplicationContext().getBean(handlerName);
    }

    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    
    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        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个步骤

  1. 根据request获取到handler,若没匹配上,会返回容器一个默认的handler
  2. 找到interceptor,封装成HandlerExecutionChain 对象
  3. 若有跨域的相关配置,则加上跨域的拦截器

先看下第一个步骤

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//拿到请求的路径  如:/student/getStudent
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

根据请求路径和请求对象查找HandlerMethod对象

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        addMatchingMappings(directPathMatches, matches, request);
    }
//省略...
    if (!matches.isEmpty()) {
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            bestMatch = matches.get(0);
            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 + "}");
            }
        }
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        handleMatch(bestMatch.mapping, lookupPath, request);
        return bestMatch.handlerMethod;
    }
    else {
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

根据请求路径去从map查找(上篇文章有详细的描述),获取匹配到的RequestMappingInfo列表。最终再拿到一个HandlerMethod对象。

找到HandlerMethod对象后,再查找interceptor,封装成HandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    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;
}

添加interceptor时分判断是否为MappedInterceptor,这种需要根据请求路径做匹配,匹配上的才会添加,还有一种是通用的,每个请求都会加上的,比如ConversionServiceExposingInterceptor

获取到HandlerExecutionChain后,会根据是否有跨域配置,若有的话,加上跨域的处理器

protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
        HandlerExecutionChain chain, @Nullable CorsConfiguration config) {

    if (CorsUtils.isPreFlightRequest(request)) {
        HandlerInterceptor[] interceptors = chain.getInterceptors();
        return new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
    }
    else {
        chain.addInterceptor(0, new CorsInterceptor(config));
        return chain;
    }
}

当根据request拿到最终要执行的HandlerExecutionChain后,在执行具体的controller的方法前后,及方法执行完毕后,会先执行拦截器的几个回调方法。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //省略.....
    try {
        ModelAndView mv = null;
        Exception dispatchException = null;
        try {
    //省略
//拿到HandlerExecutionChain对象
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }
//先执行拦截器的preHandle方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 执行具体controller的方法
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//执行拦截器的postHandle方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        //执行拦截器的afterCompletion方法
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
//即使有异常抛出,也会执行拦截器的afterCompletion方法
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    }
    //省略
}

相关文章

网友评论

    本文标题:springmvc源码分析-HandlerMapping工作流程

    本文链接:https://www.haomeiwen.com/subject/tqlnmktx.html