博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMvc @RequestMapping原理
阅读量:5132 次
发布时间:2019-06-13

本文共 6763 字,大约阅读时间需要 22 分钟。

讲这个之前,我们得先知道在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
matches = new ArrayList
(); List
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
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); } }

 

转载于:https://www.cnblogs.com/javammc/p/8600509.html

你可能感兴趣的文章
http和https的区别
查看>>
Hbuild在线云ios打包失败,提示BuildConfigure Failed 31013 App Store 图标 未找到 解决方法...
查看>>
找到树中指定id的所有父节点
查看>>
今天新开通了博客
查看>>
AS3优化性能笔记二
查看>>
ElasticSearch(站内搜索)
查看>>
4----COM:a Generative Model for group recommendation(组推荐的一种生成模型)
查看>>
UVA 11137 - Ingenuous Cubrency
查看>>
js阻止事件冒泡的两种方法
查看>>
Java异常抛出
查看>>
[SQL Server 系] T-SQL数据库的创建与修改
查看>>
74HC164应用
查看>>
变量声明和定义的关系
查看>>
Wpf 之Canvas介绍
查看>>
linux history
查看>>
jQuery on(),live(),trigger()
查看>>
Python2.7 urlparse
查看>>
sencha touch在华为emotion ui 2.0自带浏览器中圆角溢出的bug
查看>>
【架构】Linux的架构(architecture)
查看>>
ASM 图解
查看>>