热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

浅谈SpringMVC请求映射handler源码解读

这篇文章主要介绍了浅谈SpringMVC请求映射handler源码解读,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

请求映射源码

首先看一张请求完整流转图(这里感谢博客园上这位大神的图,博客地址我忘记了):

前台发送给后台的访问请求是如何找到对应的控制器映射并执行后续的后台操作呢,其核心为DispatcherServlet.java与HandlerMapper。在spring boot初始化的时候,将会加载所有的请求与对应的处理器映射为HandlerMapper组件。我们可以在springMVC的自动配置类中找到对应的Bean。

@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(
  @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
  @Qualifier("mvcConversionService") FormattingConversionService conversionService,
  @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
  // Must be @Primary for MvcUriComponentsBuilder to work
  return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
                       resourceUrlProvider);
}

@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
                              FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
  WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
    new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
    this.mvcProperties.getStaticPathPattern());
  welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
  welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
  return welcomePageHandlerMapping;
}

请求将首先执行FrameworkServlet下的service方法根据request请求的method找到对应的do**方法。

@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {

  HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
  if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
    processRequest(request, response);
  }
  else {
    //父类根据method参数执行doGet,doPost,doDelete等
    super.service(request, response);
  }
}

而这些do**其都会进入核心方法,以doGet为例。

@Overrideprotected 
final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  //核心方法
  processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
  try {
  //进入此核心方法
  doService(request, response);
}
catch (ServletException | IOException ex) {
  failureCause = ex;
  throw ex;
}
catch (Throwable ex) {
  failureCause = ex;
  throw new NestedServletException("Request processing failed", ex);
}

finally {
  resetContextHolders(request, previousLocaleContext, previousAttributes);
  if (requestAttributes != null) {
    requestAttributes.requestCompleted();
  }
  logResult(request, response, failureCause, asyncManager);
  publishRequestHandledEvent(request, response, startTime, failureCause);
}

processRequest()方法中重点在doService(request, response);,而其核心处理逻辑位于DispatchServletl类重写的方法,如下。

@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
 ····

   try {
     //这里为实际分发控制器的逻辑,其内部是找到对应的handlerMapper
     doDispatch(request, response);
   }
    finally {
      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        // Restore the original attribute snapshot, in case of an include.
        if (attributesSnapshot != null) {
          restoreAttributesAfterInclude(request, attributesSnapshot);
        }
      }
      if (requestPath != null) {
        ServletRequestPathUtils.clearParsedRequestPath(request);
      }
    }
}

接下来看分发处理逻辑方法,其中重要的方法都使用了原生的注释。接下来分别分析核心源码。

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) {
        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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
          return;
        }
      }

      if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
      }

      // Actually invoke the handler.
      mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

      if (asyncManager.isConcurrentHandlingStarted()) {
        return;
      }

      applyDefaultViewName(processedRequest, mv);
      mappedHandler.applyPostHandle(processedRequest, response, mv);
    }
    catch (Exception ex) {
      dispatchException = ex;
    }
    catch (Throwable err) {
      // As of 4.3, we're processing Errors thrown from handler methods as well,
      // making them available for @ExceptionHandler methods and other scenarios.
      dispatchException = new NestedServletException("Handler dispatch failed", err);
    }
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  }
  catch (Exception ex) {
    triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  }
  catch (Throwable err) {
    triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
  }
  finally {
    if (asyncManager.isConcurrentHandlingStarted()) {
      // Instead of postHandle and afterCompletion
      if (mappedHandler != null) {
        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
      }
    }
    else {
      // Clean up any resources used by a multipart request.
      if (multipartRequestParsed) {
        cleanupMultipart(processedRequest);
      }
    }
  }
}

首先是分析getHandler(),找到对应的处理器映射逻辑。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  if (this.handlerMappings != null) {
    for (HandlerMapping mapping : this.handlerMappings) {
      HandlerExecutionChain handler = mapping.getHandler(request);
      if (handler != null) {
        return handler;
      }
    }
  }
  return null;
}

我们将断点标记在getHandler方法上时,可以清除看到handlerMappings,如图。

这里,用户请求与处理器的映射关系都在RequestMapperHandlerMapping中,而欢迎页处理请求则在WelcomePageHanderMapping中进行映射。

以下为RequestMapperHandlerMapping中映射部分截图,可以看到用户的所有请求映射这里面都有:

getHandler()后的方法是通过比较request请求中method与HandlerMapper中相同url下的method,再进行唯一性校验,不通过异常,通过找到唯一的handler。

后续,通过handler找到处理的设配器,通过适配器得到一个ModelAndView对象,这个对象就是最后返回给前端页面的对象。

至此,一个请求完整映射到返回前端结束。

说明:这是实现了FramworkServlet的doService方法,FramworkServlet继承自HttpServlet,并且重写了父类中的doGet(),doPost(),doPut(),doDelete 等方法,在这些重写的方法里都调用了 processRquest() 方法做请求处理,进入processRquest()可以看到里面调用了FramworkServlet中定义的doService() 方法。

到此这篇关于浅谈SpringMVC请求映射handler源码解读的文章就介绍到这了,更多相关SpringMVC请求映射handler 内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 题目描述:小K不幸被LL邪教洗脑,洗脑程度之深使他决定彻底脱离这个邪教。在最终离开前,他计划再进行一次亚瑟王游戏。作为最后一战,他希望这次游戏能够尽善尽美。众所周知,亚瑟王游戏的结果很大程度上取决于运气,但通过合理的策略和算法优化,可以提高获胜的概率。本文将详细解析洛谷P3239 [HNOI2015] 亚瑟王问题,并提供具体的算法实现方法,帮助读者更好地理解和应用相关技术。 ... [详细]
  • 本文详细介绍了如何在Linux系统中搭建51单片机的开发与编程环境,重点讲解了使用Makefile进行项目管理的方法。首先,文章指导读者安装SDCC(Small Device C Compiler),这是一个专为小型设备设计的C语言编译器,适合用于51单片机的开发。随后,通过具体的实例演示了如何配置Makefile文件,以实现代码的自动化编译与链接过程,从而提高开发效率。此外,还提供了常见问题的解决方案及优化建议,帮助开发者快速上手并解决实际开发中可能遇到的技术难题。 ... [详细]
  • 2019年后蚂蚁集团与拼多多面试经验详述与深度剖析
    2019年后蚂蚁集团与拼多多面试经验详述与深度剖析 ... [详细]
  • Python作为当今IT领域中最受欢迎且高效的语言之一,其框架能够显著加速Web应用程序的开发过程。本文推荐并对比了十大顶级Python Web开发框架,其中CubicWeb以其卓越的代码重用性和模块化设计脱颖而出,为开发者提供了强大的支持。 ... [详细]
  • 在Hive中合理配置Map和Reduce任务的数量对于优化不同场景下的性能至关重要。本文探讨了如何控制Hive任务中的Map数量,分析了当输入数据超过128MB时是否会自动拆分,以及Map数量是否越多越好的问题。通过实际案例和实验数据,本文提供了具体的配置建议,帮助用户在不同场景下实现最佳性能。 ... [详细]
  • 在稀疏直接法视觉里程计中,通过优化特征点并采用基于光度误差最小化的灰度图像线性插值技术,提高了定位精度。该方法通过对空间点的非齐次和齐次表示进行处理,利用RGB-D传感器获取的3D坐标信息,在两帧图像之间实现精确匹配,有效减少了光度误差,提升了系统的鲁棒性和稳定性。 ... [详细]
  • 本文探讨了在Android应用中实现动态滚动文本显示控件的优化方法。通过详细分析焦点管理机制,特别是通过设置返回值为`true`来确保焦点不会被其他控件抢占,从而提升滚动文本的流畅性和用户体验。具体实现中,对`MarqueeText.java`进行了代码层面的优化,增强了控件的稳定性和兼容性。 ... [详细]
  • 本文深入探讨了数据库性能优化与管理策略,通过实例分析和理论研究,详细阐述了如何有效提升数据库系统的响应速度和处理能力。文章首先介绍了数据库性能优化的基本原则和常用技术,包括索引优化、查询优化和存储管理等。接着,结合实际应用场景,讨论了如何利用容器化技术(如Docker)来部署和管理数据库,以提高系统的可扩展性和稳定性。最后,文章还提供了具体的配置示例和最佳实践,帮助读者在实际工作中更好地应用这些策略。 ... [详细]
  • 当前,众多初创企业对全栈工程师的需求日益增长,但市场中却存在大量所谓的“伪全栈工程师”,尤其是那些仅掌握了Node.js技能的前端开发人员。本文旨在深入探讨全栈工程师在现代技术生态中的真实角色与价值,澄清对这一角色的误解,并强调真正的全栈工程师应具备全面的技术栈和综合解决问题的能力。 ... [详细]
  • 全面解析:Hadoop技术栈中的Linux操作系统概览
    全面解析:Hadoop技术栈中的Linux操作系统概览 ... [详细]
  • 在使用关系型数据库时,通常需要通过用户名和密码进行身份验证才能访问数据。然而,MongoDB默认情况下并不强制要求这种身份验证机制,使得用户无需凭据即可访问并执行各种操作。虽然这一设计简化了初学者的上手过程,但也带来了显著的安全风险。为了提升MongoDB的连接安全性,本文将探讨多种策略与实践,包括启用身份验证、配置网络访问控制、加密通信以及定期审计安全设置,以确保数据库的安全性和数据的完整性。 ... [详细]
  • 题目《UVa 11978 福岛核爆问题》涉及圆与多边形交集面积的计算及二分法的应用。该问题的核心在于通过精确的几何运算与高效的算法实现来解决复杂图形的面积计算。在实现过程中,特别需要注意的是对多边形顶点的平移处理,确保所有顶点包括最后一个顶点 \( p[n] \) 都经过正确的位移,以避免因细节疏忽导致的错误。此外,使用循环次数为50次的二分法能够有效提高算法的精度和稳定性。 ... [详细]
  • SQLmap自动化注入工具命令详解(第28-29天 实战演练)
    SQL注入工具如SQLMap等在网络安全测试中广泛应用。SQLMap是一款开源的自动化SQL注入工具,支持12种不同的数据库,具体支持的数据库类型可在其插件目录中查看。作为当前最强大的注入工具之一,SQLMap在实际应用中具有极高的效率和准确性。 ... [详细]
  • 视觉图像的生成机制与英文术语解析
    近期,Google Brain、牛津大学和清华大学等多家研究机构相继发布了关于多层感知机(MLP)在视觉图像分类中的应用成果。这些研究深入探讨了MLP在视觉任务中的工作机制,并解析了相关技术术语,为理解视觉图像生成提供了新的视角和方法。 ... [详细]
  • POJ 1696: 空间蚂蚁算法优化与分析
    针对 POJ 1696 的空间蚂蚁算法进行了深入的优化与分析。本研究通过改进算法的时间复杂度和空间复杂度,显著提升了算法的效率。实验结果表明,优化后的算法在处理大规模数据时表现优异,能够有效减少计算时间和内存消耗。此外,我们还对算法的收敛性和稳定性进行了详细探讨,为实际应用提供了可靠的理论支持。 ... [详细]
author-avatar
书友55218170
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有