SpringMvc @RequestMapping原理详解

KLQ 2020-07-23 15:56:48 java常见问答 7276

之前给大家介绍过@requestmapping注解方面的内容,那么接下来要给大家介绍的就是@RequestMapping原理,一起来了解一下吧。

首先我们要知道,springmvc启动的时候,会加载所有的Bean类,也就是加了@Controller,@Component等组件标识的类,之后,会将@RequestMapping的方法也加入到一个集合。

放入到上下文环境中。

下面是发起请求之后的执行流程:检查request类型--获取匹配的Handlemethod--查找拦截器--组成HandlerExecutionChain执行链--获取方法执行链对象的适配器(HandlerAdapter)--之后反射执行业务方法。

再来看一下源码分析:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception
{
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try
    {
        ModelAndView mv = null;
        Exception dispatchException = null;
        try
        {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = processedRequest != request;
            // Determine handler for the current request.
            //获取匹配的执行链
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null || mappedHandler.getHandler() == null)
            {
                noHandlerFound(processedRequest, response);
                return;
            }
            // Determine handler adapter for the current request.
            //根据匹配到的执行链对象,获取合适的适配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method))
            {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled())
                {
                    String requestUri = urlPathHelper.getRequestUri(request);
                    logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response)
                    .checkNotModified(lastModified) && isGet)
                {
                    return;
                }
            }
            if (!mappedHandler.applyPreHandle(processedRequest, response))
            {
                return;
            }
            try
            {
                // Actually invoke the handler.
                //在这里面反射执行业务方法
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            }
            finally
            {
                if (asyncManager.isConcurrentHandlingStarted())
                {
                    return;
                }
            }
            applyDefaultViewName(request, mv);
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex)
        {
            dispatchException = ex;
        }
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex)
    {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Error err)
    {
        triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
    }
    finally
    {
        if (asyncManager.isConcurrentHandlingStarted())
        {
            // Instead of postHandle and afterCompletion
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            return;
        }
        // Clean up any resources used by a multipart request.
        if (multipartRequestParsed)
        {
            cleanupMultipart(processedRequest);
        }
    }
}

从标红部分点进去,到AbstractHandlerMethodAdapter类的handle方法--RequestMappingHandlerAdapter类的handleInternal方法--RequestMappingHandlerAdapter类的invokeHandleMethod--RequestMappingHandlerAdapter类的invokeAndHandle--ServletInvocableHandlerMethod类的invokeForRequest--InvocableHandlerMethod类的invokeForRequest。

方法代码:

public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer
    , Object...providedArgs) throws Exception
{
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled())
    {
        StringBuilder sb = new StringBuilder("Invoking [");
        sb.append(this.getBeanType()
                .getSimpleName())
            .append(".");
        sb.append(getMethod()
                .getName())
            .append("] method with arguments ");
        sb.append(Arrays.asList(args));
        logger.trace(sb.toString());
    }
    //执行方法
    Object returnValue = invoke(args);
    if (logger.isTraceEnabled())
    {
        logger.trace("Method [" + getMethod()
            .getName() + "] returned [" + returnValue + "]");
    }
    return returnValue;
}

之后,执行方法。

这里的话要注意一下匹配方法的时候,依据@RequestMapping里面的value路径来匹配的。

假如,匹配到的有多个,例如,匹配到了通配符,也配置了精确配置,就都会匹配到放在一个集合中,依据规则排序,之后取集合的第一个元素。

具体代码实现:

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception
{
    List < Match > matches = new ArrayList < Match > ();
    List < T > directPathMatches = this.urlMap.get(lookupPath);
    if (directPathMatches != null)
    {
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty())
    {
        // No choice but to go through all mappings
        addMatchingMappings(this.handlerMethods.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)
        {
            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(handlerMethods.keySet(), lookupPath, request);
    }
}

你想成为一名优秀的java架构师吗?请继续的关注奇Q工具网吧,有更多这方面的知识点可以为你分享。