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方法


相关文章
|
25天前
|
Rust 前端开发 API
Tauri 开发实践 — Tauri HTTP 请求开发
本文介绍了如何在 Tauri 中发起 HTTP 请求。首先通过安装 Tauri 生态中的工具包并配置 `tauri.conf.json` 文件来允许特定域名的 HTTP 通信。接着封装了一个简单的 HTTP 客户端类,并在页面中使用该客户端实现 GET 和 POST 请求。最后提供了完整的源码地址以供参考。此功能使得桌面应用能够与远程服务器进行交互,增强了应用的实用性。
69 1
Tauri 开发实践 — Tauri HTTP 请求开发
|
5天前
|
缓存 前端开发 API
|
10天前
|
数据采集 前端开发 算法
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
本文介绍了如何使用 Python 的 `requests` 库应对复杂的 HTTP 请求场景,包括 Spider Trap(蜘蛛陷阱)、SESSION 访问限制和请求频率限制。通过代理、CSS 类链接数控制、多账号切换和限流算法等技术手段,提高爬虫的稳定性和效率,增强在反爬虫环境中的生存能力。文中提供了详细的代码示例,帮助读者掌握这些高级用法。
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
|
20小时前
|
开发者
HTTP 协议请求方法的发展历程
【10月更文挑战第21天】
|
21小时前
|
安全
HTTP 协议的请求方法
【10月更文挑战第21天】
|
20小时前
|
缓存 安全 前端开发
HTTP 协议的请求方法在实际应用中有哪些注意事项?
【10月更文挑战第29天】HTTP协议的请求方法在实际应用中需要根据具体的业务场景和需求,合理选择和使用,并注意各种方法的特点和限制,以确保网络通信的安全、高效和数据的一致性。
|
4天前
|
安全 API 数据安全/隐私保护
常见的HTTP请求方法
【10月更文挑战第25天】这些HTTP请求方法共同构成了客户端与服务器之间交互的基础,使得客户端能够根据不同的需求对服务器资源进行各种操作。在实际应用中,开发者需要根据具体的业务场景和资源的性质选择合适的请求方法来实现客户端与服务器之间的有效通信。
|
11天前
|
网络协议
Lua中实现异步HTTP请求的方法
Lua中实现异步HTTP请求的方法
|
9天前
|
存储 安全 网络协议
HTTP 请求方法
【10月更文挑战第22天】HTTP 请求方法
17 2
|
9天前
|
缓存 JSON 安全
HTTP请求发送方法
HTTP请求发送方法【10月更文挑战第22天】
18 2