SpringMVC已经是广大Java程序员很熟悉的东西了,虽然现在已经大量使用SpringBoot和SpringCloud,但是其底层都是对SpringMVC的封装。
相信大家都用过SpringMVC的路径变量吧,代码示例如下:
如上所示,id参数就是路径变量,{id}起到一个占位符的作用,在执行具体请求方法test()的时候,SpringMVC通过@PathVariable注解取到{id}对应的参数值,再通过反射赋值给String id这个参数。
但是一个项目中如果使用了大量的这种带有路径变量的@RequestMapping,会带来一定的性能问题。具体原因下面会详细说明,在此之前,先来梳理一下SpringMVC的请求执行流程。
SpringMVC的请求执行流程回顾
- 用户发起请求,请求由中央调度器DispatcherServlet接收,执行doDispatch方法;
- 中央调度器根据请求信息从处理器映射器中找到请求执行链(拦截器+自定义的处理器Controller);
- 中央调度器根据处理器类型获取到处理器适配器,通过处理器适配器先执行拦截器中的preHandler()方法,再执行自定义处理器中的方法;
- 适配器执行完自定义处理器方法后得到一个ModelAndView,然后再执行拦截器的PostHandle()方法;
- 中央调度器把ModelAndView交给视图解析器处理,得到一个视图(view)对象,然后将模型数据填充到视图(view);
- 把模型数据和View合并输出到Response(应答对象),即渲染视图,用户能看到的处理结果页面。
- 最后执行拦截器的afterCompletion()方法,执行流程结束。
SpringMVC根据请求Url找到对应处理器方法的过程
- 首先,SpringMVC容器在加载的时候,会扫描所有的@Controller或者@RestController修饰的类,将这些类中的@RequestMapping修饰的方法存放到处理器映射器(底层就是ConcurrentHashMap)中,存放的时候以@RequestMapping中声明的url作为key,对应方法的反射信息作为value;
- 用户请求到达中央调度器之后,会根据用户请求的url去处理器映射器中找到对应的处理器方法,然后交给处理器适配器,完成方法的执行,最后经过一系列梳理将数据返回给前端。
带有Url路径变量的请求问题
我们知道,如果是一个不带路径变量的请求url,则直接可以从处理器映射器的Map集合中精确匹配到对应的处理器方法。那带有路径参数的url呢,Map集合的key比如是 /test/{id},而浏览器请求的url是/test/1,浏览器的请求url这个时候相当于是动态的,显然无法直接匹配到对应的处理器方法。

那么SpringMVC是如何匹配url请求变量的呢?
我个人刚开始以为SpringMVC采用了什么高深的技术,于是就找时间看了下源码,核心代码在SpringMVC的这个方法:
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod
讯享网
java获取request的基础域名
如上图Debug所示,SpringMVC要从这一大堆的映射关系中通过for循环遍历去一个一个匹配判断,然后找到带有路径变量的url对应的处理器映射关系,如果项目中 @RequestMapping声明非常多的话,这将是一个非常耗时的过程。
总结
本人刚开始以为SpringMVC肯定会采用很高深高效的方式去解决带有路径变量Url的匹配问题,但是通过对源码的分析,其实并没有,依然采用了我们最能想到的循环遍历方式,这样一个O(n)复杂度的匹配过程。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/3638.html