06初始化HandlerMapping并根据Http请求获取HandlerExecutionChain

简介: 初始化HandlerMapping根据request获取对应的HandlerExecutionChainRequestMappingHandlerMapping体系实现获取HandlerExecutionChain

内容概览


  • 初始化HandlerMapping
  • 根据request获取对应的HandlerExecutionChain
  • RequestMappingHandlerMapping体系实现获取HandlerExecutionChain


初始化HandlerMapping


前面注册RequestMapping和Handler的映射关系时声明的RequestMappingHandlerMapping就是HandlerMapping的一个实现。该接口中定义了一个方法getHandler就是返回当前请求的Handler或者拦截器。这个匹配的过程可能取决于请求的URL、session的状态或者其他的原因,由具体的实现决定。如果找到匹配结果就会返回一个HandlerExecutionChain对象,HandlerExecutionChain封装了Handler和拦截器。


   /**

    * Return a handler and any interceptors for this request.

    */

   @Nullable

   HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;


DispatcherServlet的initHandlerMappings


在DispatcherServlet类中的initHandlerMappings就是获取上下文中的HandlerMapping。这里做了简化没有对获取不到使用默认策略进行展示。


   private void initHandlerMappings(ApplicationContext context) {

       this.handlerMappings = null;

       //Find all HandlerMappings in the ApplicationContext, including ancestor contexts.

       Map<String, HandlerMapping> matchingBeans =

               BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);

       if (!matchingBeans.isEmpty()) {

           this.handlerMappings = new ArrayList<>(matchingBeans.values());

           //We keep HandlerMappings in sorted order.

           AnnotationAwareOrderComparator.sort(this.handlerMappings);

       }

   }


根据request获取对应的HandlerExecutionChain


现在的DispatcherServlet已经匹配了所有的Http请求,并且交给方法doDispatch方法去处理,因此在该方法中首先就是获取当前请求的Handler。


   protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {


       HttpServletRequest processedRequest = request;



       HandlerExecutionChain mappedHandler = getHandler(processedRequest);

       if (null == mappedHandler) {

           noHandlerFound(processedRequest, response);

           return;

       }


   }


   /**

    * Return the HandlerExecutionChain for this request.

    */

   @Nullable

   protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

       if (null != this.handlerMappings) {

           for (HandlerMapping mapping : this.handlerMappings) {

               HandlerExecutionChain handler = mapping.getHandler(request);

               if (null != handler) {

                   return handler;

               }

           }

       }

       return null;

   }


这两小块代码就是获取Handler的主干,具体详细的获取操作交给HandlerMapping的实现体系。


RequestMappingHandlerMapping体系实现获取HandlerExecutionChain


RequestMappingHandlerMapping类结构图



根据请求获取Handler的流程图



AbstractHandlerMapping的getHandler方法


   @Override

   public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

       Object handler = getHandlerInternal(request);


       return getHandlerExecutionChain(handler, request);

   }


   protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {


       return handler instanceof HandlerExecutionChain ?

               (HandlerExecutionChain) handler :

               new HandlerExecutionChain(handler);

   }


DispatcherServlet中会调用getHandler方法。AbstractHandlerMapping实现了HandlerMapping的getHandler方法,然后调用模版方法getHandlerInternal获取当前请求匹配的handler。最后将获取到的Handler包装成HandlerExecutionChain。


AbstractHandlerMethodMapping实现的getHandlerInternal


   @Override

   @Nullable

   protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {

       String lookupPath = initLookupPath(request);

       HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

       return null != handlerMethod ? handlerMethod.createWithResolvedBean() : null;

   }


  • 首先调用父类方法initLookupPath获取当前请求的URL,实际上调用的是UrlPathHelper类中的方法。
  • 然后调用lookupHandlerMethod根据请求URL获取最佳匹配的HandlerMethod
  • 最后就是返回HandlerMethod或者null


AbstractHandlerMethodMapping的lookupHandlerMethod方法


   /**

    * Look up the best-matching handler method for the current request. If multiple

    * matches are found, the best match is selected.

    */

   @Nullable

   protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {

       List<Match> matches = new ArrayList<>();

       //1.根据请求URL获取RequestMappingInfo

       List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);

       if (null != directPathMatches) {

           //2.从RequestMappingInfo中构造Match放到matches中

           addMatchingMapping(directPathMatches, matches, request);

       }

       if (matches.isEmpty()) {

           addMatchingMapping(this.mappingRegistry.getRegistration().keySet(), matches, request);

       }

       //3.获取最佳匹配的结果

       if (!matches.isEmpty()) {

           Match bestMatch = matches.get(0);


           request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());

           handleMatch(bestMatch.mapping, lookupPath, request);

           return bestMatch.getHandlerMethod();

       } else {

           //返回没有匹配的结果

           return handleNoMatch(this.mappingRegistry.getRegistration().keySet(), lookupPath, request);

       }

   }


   private void addMatchingMapping(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {

       for (T mapping : mappings) {

           T match = getMatchingMapping(mapping, request);

           if (null != match) {

               matches.add(new Match(match, this.mappingRegistry.getRegistration().get(mapping)));

           }

       }

   }


  1. this.mappingRegistry是AbstractHandlerMethodMapping的内部类MappingRegistry,MappingRegistry维护了请求URL和RequestMappingInfo的关系。这个后面专门描述一下这个关系的创建及获取过程,这里只要知道是根据请求的URL从map中获取匹配的RequestMappingInfo即可。
  2. 遍历匹配的RequestMappingInfo并从中构造Match放到matches中,遍历的过程会调用模版方法getMatchingMapping
  3. 这里是获取最佳匹配的结果,这里简化了,实际上会进行compare获取最优的一个
  4. 如果没有匹配的则返回对应的标识


RequestMappingInfoHandlerMapping的getMatchingMapping


   @Override

   protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {

       return info.getMatchingCondition(request);

   }


这里只能说RequestMappingInfo维护了获取的逻辑。也留到RequestMappingInfo里一起描述吧。


测试


调用example-easy-spring中的测试接口



DispatcherServlet中断点查看


在DispatcherServlet中getHandler方法调用后面断点,可以看到获取到了beanController中的beans方法


相关文章
|
2月前
|
Rust 前端开发 API
Tauri 开发实践 — Tauri HTTP 请求开发
本文介绍了如何在 Tauri 中发起 HTTP 请求。首先通过安装 Tauri 生态中的工具包并配置 `tauri.conf.json` 文件来允许特定域名的 HTTP 通信。接着封装了一个简单的 HTTP 客户端类,并在页面中使用该客户端实现 GET 和 POST 请求。最后提供了完整的源码地址以供参考。此功能使得桌面应用能够与远程服务器进行交互,增强了应用的实用性。
153 1
Tauri 开发实践 — Tauri HTTP 请求开发
|
17天前
|
JSON Java 数据格式
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
67 25
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
|
15天前
|
Web App开发 大数据 应用服务中间件
什么是 HTTP Range请求(范围请求)
HTTP Range 请求是一种非常有用的 HTTP 功能,允许客户端请求资源的特定部分,从而提高传输效率和用户体验。通过合理使用 Range 请求,可以实现断点续传、视频流播放和按需加载等功能。了解并掌握 HTTP Range 请求的工作原理和应用场景,对开发高效的网络应用至关重要。
55 15
|
19天前
|
数据采集 JSON 测试技术
Grequests,非常 Nice 的 Python 异步 HTTP 请求神器
在Python开发中,处理HTTP请求至关重要。`grequests`库基于`requests`,支持异步请求,通过`gevent`实现并发,提高性能。本文介绍了`grequests`的安装、基本与高级功能,如GET/POST请求、并发控制等,并探讨其在实际项目中的应用。
28 3
|
24天前
|
前端开发 UED 开发者
CSS Sprites和图标字体在网页图标加载优化中的应用。CSS Sprites通过合并多图标减少HTTP请求,提升加载速度
本文探讨了CSS Sprites和图标字体在网页图标加载优化中的应用。CSS Sprites通过合并多图标减少HTTP请求,提升加载速度;图标字体则以字体形式呈现图标,便于调整样式。文章分析了两者的优缺点及应用场景,并提供了应用技巧和注意事项,旨在帮助开发者提升页面性能,改善用户体验。
23 5
|
1月前
|
缓存 前端开发 API
|
2月前
|
数据采集 前端开发 算法
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
本文介绍了如何使用 Python 的 `requests` 库应对复杂的 HTTP 请求场景,包括 Spider Trap(蜘蛛陷阱)、SESSION 访问限制和请求频率限制。通过代理、CSS 类链接数控制、多账号切换和限流算法等技术手段,提高爬虫的稳定性和效率,增强在反爬虫环境中的生存能力。文中提供了详细的代码示例,帮助读者掌握这些高级用法。
114 1
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
|
1月前
|
JSON API 数据格式
Python中获取HTTP请求响应体的详解
本文介绍了如何使用Python的`requests`和`urllib`库发送HTTP请求并处理响应体。`requests`库简化了HTTP请求过程,适合快速开发;`urllib`库则更为底层,适用于性能要求较高的场景。文章详细演示了发送GET请求、处理JSON响应等常见操作。
47 3
|
1月前
|
安全 API 网络安全
使用OkHttp进行HTTPS请求的Kotlin实现
使用OkHttp进行HTTPS请求的Kotlin实现
|
16天前
|
Web App开发 网络安全 数据安全/隐私保护
Lua中实现HTTP请求的User-Agent自定义
Lua中实现HTTP请求的User-Agent自定义
下一篇
DataWorks